沙盒苹果支付测试握手失败

Sandbox apple pay testing handshake failure

我在 Apple Pay 沙箱环境中验证商家时遇到问题。取自 https://developer.apple.com/reference/applepayjs/applepaysession#2166532,一旦我的 server then calls the Start Session endpoint at the provided URL,我得到一个 500 错误。

我查了一下,这个 500 错误发生在网络层的某个地方。正如苹果页面(https://developer.apple.com/reference/applepayjs/)所列,我需要满足以下要求:

  1. 所有包含 Apple Pay 的页面都必须通过 HTTPS 提供。 完成,服务器 ssl/https 全站
  2. 要启用商家验证,您的服务器必须允许通过 HTTPS(端口 443 上的 TCP)访问下面清单 1 中提供的 Apple Pay IP 地址。 完成,服务器对端口 443 上的所有 ips 开放
  3. 您的服务器必须支持传输层安全 (TLS) 1.2 协议和 Table 1 中列出的密码套件之一。服务器支持 tls 1.2,因为我在 tls 上发送请求1.2 到apple pay的开发服务器(下)

我一直在使用 Wireshark 检查发生了什么,一旦服务器发回密码规范后,服务器处于 ChangeCipherSpec 阶段,我似乎就失败了给客户。 (ssl 过程参考:https://support.f5.com/csp/article/K15292)。正如您从我的图像中看到的那样,我正在与 apple pay 沙箱服务器通信,传递错误提示的相同受支持的 tls 协议和密码套件 -> Handshake Failure (40),所以发生了其他事情,我不知道去哪里看

如果您查看 ServerHello 消息,您可以看到服务器找到并接受了与客户端匹配的密码套件,这也与 apple pay 支持的所需密码之一匹配

我可以根据需要添加其他详细信息

问题是我们的服务器没有默认启用 TLS 1.2。启用 TLS 1.2 并禁用 TLS 1.0 解决了这个问题 - Win 2008

编辑

有几件事需要发生。我们的服务器在 .net 4.5 上,默认情况下不使用 tls 1.2(苹果要求使用 tls 1.2)。因此,我们将解决方案升级到 .net 4.6,并针对我们的请求强制使用 tls 1.2。此外,我们必须在我们对苹果的请求中包含商家 ID 证书(文档中没有很好地提及)。

您可以找到我在此处使用的源代码的 github 存储库 (https://github.com/justeat/ApplePayJSSample),但这是我需要放入我的解决方案以使事情正常运行的代码(我也有从我的 mac 的钥匙串中导出我的商家证书,它给了我一个 .p12 文件。我将这个 .p12 文件导入到我服务器的 计算机 证书存储中)

[System.Web.Http.HttpPost]
    public async Task<ContentResult> GetApplePaySession([FromBody] string url)
    {
        // 
        System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

        // Load the merchant certificate for two-way TLS authentication with the Apple Pay server.
        var certificate = LoadMerchantCertificate();

        // Get the merchant identifier from the certificate to send in the validation payload.
        var merchantIdentifier = GetMerchantIdentifier(certificate);

        // Create the JSON payload to POST to the Apple Pay merchant validation URL.
        var payload = new ApplePayRequest()
        {
            merchantIdentifier = merchantIdentifier,
            domainName = System.Web.HttpContext.Current.Request.Url.Host,
            displayName = "[display name from apple developer portal]"
        };

        JObject merchantSession;

        // Create an HTTP client with the merchant certificate
        // for two-way TLS authentication over HTTPS.
        using (var httpClient = CreateHttpClient(certificate))
        {
            var jsonPayload = JsonConvert.SerializeObject(payload);

            using (var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"))
            {
                // POST the data to create a valid Apple Pay merchant session.
                using (var response = await httpClient.PostAsync(url, content))
                {
                    response.EnsureSuccessStatusCode();

                    // Read the opaque merchant session JSON from the response body.
                    var merchantSessionJson = await response.Content.ReadAsStringAsync();
                    merchantSession = JObject.Parse(merchantSessionJson);
                }
            }
        }

        // Return the merchant session as JSON.
        return Content(merchantSession.ToString(), "application/json");
    }

    #region Apple Pay helper methods

    private X509Certificate2 LoadMerchantCertificate()
    {
        X509Certificate2 certificate;

        // Load the certificate from the current user's certificate store. This
        // is useful if you do not want to publish the merchant certificate with
        // your application, but it is also required to be able to use an X.509
        // certificate with a private key if the user profile is not available,
        // such as when using IIS hosting in an environment such as Microsoft Azure.
        using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
        {
            store.Open(OpenFlags.ReadOnly);

            // when using thumbprint from mmc, look at:
            // 
            // there is a hidden character that you must delete
            var certificates = store.Certificates.Find(
                X509FindType.FindByThumbprint,
                "[thumbprint]",                    
                validOnly: false);

            if (certificates.Count < 1)
            {
                throw new InvalidOperationException(
                    // ReSharper disable once UseStringInterpolation
                    string.Format(
                        "Could not find Apple Pay merchant certificate with thumbprint '{0}' from store '{1}' in location '{2}'.",
                        "‎[thumpprint]", store.Name, store.Location));
            }

            certificate = certificates[0];
        }

        return certificate;
    }

    private string GetMerchantIdentifier(X509Certificate2 certificate)
    {
        // This OID returns the ASN.1 encoded merchant identifier
        var extension = certificate.Extensions["1.2.840.113635.100.6.32"];

        // Convert the raw ASN.1 data to a string containing the ID
        return extension == null ? string.Empty : Encoding.ASCII.GetString(extension.RawData).Substring(2);            
    }

    private HttpClient CreateHttpClient(X509Certificate2 certificate)
    {
        var handler = new WebRequestHandler();
        handler.ClientCertificates.Add(certificate);

        return new HttpClient(handler, disposeHandler: true);
    }

    #endregion

我最近刚经历过这个。对我来说,我必须将 PEM 和 KEY 文件合并到 PFX 中。然后我能够 运行 使用 .net core 2.1

从 ubuntu 16.04 开始会话调用
private HttpClient CreateHttpClient()
{
    var handler = new HttpClientHandler();
    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
    handler.SslProtocols = SslProtocols.Tls12;
    handler.ClientCertificates.Add(new X509Certificate2(@"/path/yourcombinedpfx.pfx"));

    return new HttpClient(handler); ;
}