You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于CardPointe处理Google Pay数据时解密失败问题排查

CardConnect集成Google Pay生产环境解密失败(Errorcode 24)

我在网站上使用CardConnect网关集成Google Pay,JavaScript端Google Pay API已实现且运行正常,同时开发了将Google Pay payload数据解密并在CardPointe中进行令牌化的代码(data变量为Google Pay返回的payload)。开发遵循CardPointe官方指南,且网站已通过Google审核。

该功能在Google Pay测试模式下可正常运行,但切换至生产模式时,调用接口返回InternalServerError,错误信息为:

{"message":"Decryption failure","errorcode":24}

令牌化实现代码

public async Task<string> TokenizeGooglePayDataCardPointe(string data) {
    Admins adminBRs = new Admins(_context);
    string uri = adminBRs.GetPageSetting("Donations", "CardPointeURL");
    if (!uri.StartsWith("http")) uri = "https://" + uri;
    if (!uri.EndsWith("/")) uri += "/";
    string uri2 = uri + "cardsecure/api/v1/ccn/tokenize";

    dynamic obj = new System.Dynamic.ExpandoObject();
    obj.devicedata = data;
    obj.encryptionhandler = "EC_GOOGLE_PAY";
    string content = JsonConvert.SerializeObject(obj);

    var contentString = new StringContent(content, System.Text.Encoding.UTF8, "application/json");
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
    try {
        using (HttpClient client = new HttpClient()) {
            // Set request headers.
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            HttpResponseMessage response = await client.PostAsync(uri2, contentString);
            if (response != null) {
                if (response.IsSuccessStatusCode) {
                    if (response.Content != null) {
                        string jsonString = response.Content.ReadAsStringAsync().Result;
                        JObject results = JsonConvert.DeserializeObject<JObject>(jsonString);
                        JToken errorCode = results.GetValue("errorcode");
                        JToken message = results.GetValue("message");
                        if (errorCode.ToString() == "0") {
                            JToken token = results.GetValue("token");
                            return token.ToString();
                        } else {
                            return "Error: " + errorCode.ToString() + " " + message.ToString();
                        }
                    } else {
                        LogInfo.LogText(_context, "Google Pay tokenization error: no reponse content");
                        return "Error: No content returned";
                    }
                } else {
                    if (response.StatusCode == HttpStatusCode.RequestTimeout) {
                        LogInfo.LogText(_context, "Google Pay tokenization error: timeout");
                        return "Error: timeout";
                    } else {
                        string jsonString = "";
                        if (response.Content != null) jsonString = response.Content.ReadAsStringAsync().Result;
                        LogInfo.LogText(_context, "Google Pay tokenization error: " + response.StatusCode.ToString() + " " + response.ReasonPhrase + " " + jsonString + " " + data);
                        return "Error: status " + response.StatusCode.ToString();
                    }
                }
            } else {
                return "Error: no response";
            }
        }
    } catch (Exception ex) {
        LogInfo.LogError(_context, ex);
        return "Error";
    }
}

测试模式payload示例

{"signature":"MEYCIQCxG3oEWSF2NhoONkB6O7h3sbgHBQ9cQZDI9a1zkaL5PwIhAJY7g5ekerICbmzcD9ocvbsrSC7pup5zLUkBjQmE4jhD","intermediateSigningKey":{"signedKey":"{\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaYdF4BdKTIsIKDczrxSvOOU6sF6DTxkJCv5RZX140mswhcpFwfxz2GlfFRcKyOFYBCn/tFk+fOBUVxrnIIchIQ\\u003d\\u003d\",\"keyExpiration\":\"1718470102231\"}","signatures":["MEQCIELE+SRM6YsF7hL2YHEq7lkN4iM13kPGG3Gxyf3ubJvhAiBJhPFJBtywGWJPWI0O465P7QUnSB7P0zl+wtQtVYE4fQ\u003d\u003d"]},"protocolVersion":"ECv2","signedMessage":"{\"encryptedMessage\":\"k67b8MkJ/xyd2xvzwQ4aJllYcBp8Zm6DRqXanyN113kEzzUhgwrxZCAidWaWJZhUQiFm/OfrwLP1rW/UzFoHULU0tO5GQDRAQDK40A00tTzeoKZGpKeXo4uaHXUcJvpbVHTVbqL5BwR3v9O4OvyRD7/X6J1pv60RzTsxpd0+sGEnNziDVGEB2lK4y1MPxWN3NF/6IbG5XidK5ZIVv8l5D9QafZoDyARYQnup7i7jDOX2yRO5H/NJYPr2r71Cu50jmHiIyl9LCLhazBqKtlxqd0APYbrjBqEeyuaaq8USSCPJTDEoZ1bljjMiyd4/xBJY5pOqH2KFyspsb3MYZK3zWkmOrk+ui85DC7G/Hf28ZvNZjy1eq7MVPhLFGGczARH2IP8cQRZN/wBbPutK2MbHZW7LFZQ/dWA90LJY11WbniX9FZSukuQurWIS95FpLD1k6bgoMkhK5P713w\\u003d\\u003d\",\"ephemeralPublicKey\":\"BC4OLFg8aE9uZk2H2mlzu1a+aavaq2ZtEqOpiNaGWFv170lm0RfeffIYquzYw3Ybkp5WOTa/NIaUik122BuFegM\\u003d\",\"tag\":\"RY65Wy6zyDSj9zIpGfvzlSgzClfsvNqFALvcqsGhzYo\\u003d\"}"}

生产模式payload示例

{"signature":"MEQCIAo9FwgaZ8/vYsV2HhTzx3r3YALGnguYp3qLJwMUYd/pAiBTdDDrWWq4WmLCkbQBWB71vvtPpdwUXw/zNv527WfylQ\u003d\u003d","intermediateSigningKey":{"signedKey":"{\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqaR+yoImVfXIW+CRXutpeiGFmiC0FLtnKURmYF0LIbw3SEIQLe8sKwBu7Wa2VEjLTMVEMXnnSXDoy4EBfwOSTg\\u003d\\u003d\",\"keyExpiration\":\"1718469250000\"}","signatures":["MEUCIFSNA9M0hkBvdNmw7tWb9vb8vHeyoeWku2rwjtgh9j8OAiEA/cmTXhrqnAmr9inO9C6tsfjqrBpqvvIC2MVpRsaYI00\u003d"]},"protocolVersion":"ECv2","signedMessage":"{\"encryptedMessage\":\"XKUiZp1NtZAgEfJLx5IjdFAArvd4jXz62lF0ltmICvcdGk8F2T5zibO22tXFa7pZw6yfcDh43S+bVmVll9MpCdrg8Yk9T/nGIxqBwZoDLr9E53LJSs3s8mVz1skhWtOEd/Z89eE/GRml1qkqpiRpgYuohdGaC0Ea2EIE3dw8RIhHrevlwSFp1gRnmsL36SVboV7unyv95T/jQPVdwidm5rnjN2eZKOSAhPT71e5gNNMxuwZDD27ifq1WCpLPX02BIJzvpRHB6tGlB04/KPg758eqvBfL1VQuCasjDZ7LPlkO9eb3XFbLxMoxSnMOErXADvNOJhYZuaqJ9sKq7jpGbeUZjEoXd9Rw9C6EdRUhDQwb0ZTtkcoFVU+cgC+Xe2zD5KVQjaHgT9mX/zklHlosBX029LbOsbzhafLwn1lJH2PtGEbv3QkpVfRfXd/bYwv1mmV/NJ8cIo9K\",\"ephemeralPublicKey\":\"BK4KiIMRRVGwkKrbyHsFFzsFB09eyelyQKxp6Tqr3/68UXXpJ/I5Ub75O1BbvZvKwawndHSHaCguQaM83COAYxg\\u003d\",\"tag\":\"cWo2XNrVH98EVNdNLnZniWXKU2CAcImRKgHHdviQVwU\\u003d\"}"}

排查思路

  • 检查devicedata序列化逻辑:当前代码直接将data字符串赋值给obj.devicedata后序列化,可能导致双重序列化问题(把JSON字符串转义为普通字符串)。CardPointe接口可能期望devicedata是JSON对象而非字符串,可尝试先反序列化data再赋值:
    var deviceDataObj = JsonConvert.DeserializeObject(data);
    obj.devicedata = deviceDataObj;
    
  • 验证生产环境CardPointe端点:确认生产环境的CardPointeURL指向正确的生产域名,测试环境和生产环境的端点通常不同,避免调用测试端点导致密钥不匹配。
  • 检查加密密钥配置:生产环境必须使用CardConnect提供的生产专用加密密钥,测试密钥无法解密生产环境的Google Pay payload,确认后台配置的密钥与生产环境绑定。
  • 对比测试/生产请求体差异:打印并对比两种模式下最终发送的content字符串,检查devicedata的格式、转义字符是否符合接口要求,可通过日志记录完整请求体。
  • 确认Google Pay生产配置:验证Google Pay生产环境是否绑定了正确的CardConnect商户ID,支付网关配置是否完整,避免测试到生产的配置遗漏。
  • 测试TLS版本兼容性:尝试仅保留SecurityProtocolType.Tls12,部分生产端点对TLS1.3支持可能存在问题。

内容的提问来源于stack exchange,提问作者nuander

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 17:07:01