【问题标题】:C# HttpClient with X509Certificate2 - WebException: The request was aborted: Could not create SSL/TLS secure channel带有 X509Certificate2 的 C# HttpClient - WebException:请求被中止:无法创建 SSL/TLS 安全通道
【发布时间】:2017-10-22 04:13:39
【问题描述】:

我正在实施一项名为 Swish 的支付服务,并使用本指南对其进行测试(指南是英文的,尽管文件名是瑞典语)。

https://www.getswish.se/content/uploads/2015/06/Guide-Testverktyg_20151210.zip

如您所见,测试项目包含两个证书,.p12.pem 文件。我已尝试对两者的请求进行身份验证。

但是,即使我尝试了解决此问题的解决方案,我仍然会收到错误消息。

正如here 建议的那样,我实现了日志记录,结果是this。由于字符限制,Pastebin 链接。我在日志中没有看到任何指向 StatusCode=401 的内容,所以我认为它不是 HTTP 401 Unauthorized

public class PaymentRequest
{
    [JsonProperty("payeePaymentReference")]
    public string PayeePaymentReference { get; set; }

    [JsonProperty("callbackUrl")]
    public string CallbackUrl { get; set; }

    [JsonProperty("payerAlias")]
    public string PayerAlias { get; set; }

    [JsonProperty("payeeAlias")]
    public string PayeeAlias { get; set; }

    [JsonProperty("amount")]
    public string Amount { get; set; }

    [JsonProperty("currency")]
    public string Currency { get; set; }

    [JsonProperty("message")]
    public string Message { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var service = new SwishService();

        var paymentRequest = new PaymentRequest();
        paymentRequest.PayeePaymentReference = "0123456789";
        paymentRequest.CallbackUrl = "https://example.com/api/swishcb/paymentrequests";
        paymentRequest.PayerAlias = "4671234768";
        paymentRequest.PayeeAlias = "1231181189";
        paymentRequest.Amount = "100";
        paymentRequest.Currency = "SEK";
        paymentRequest.Message = "Kingston USB Flash Drive 8 GB";

        service.SendPaymentRequest(paymentRequest);
    }
}

public class SwishService
{
    private HttpClient client;
    public SwishService()
    {
        var baseAddress = new Uri("https://mss.swicpc.bankgirot.se");

        var certHandler = new WebRequestHandler();
        certHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
        certHandler.UseDefaultCredentials = false;

        //Same result with Swish Merchant Test Certificate 1231181189.p12 file
        var certPath = $"C:\\Users\\<Path>\\Testcertifikat\\Test Swish Root CA v1 Test.pem";

        var certificate = new X509Certificate2(certPath, "swish");
        certHandler.ClientCertificates.Add(certificate);

        client = new HttpClient(new LoggingHandler(certHandler));
        client.BaseAddress = baseAddress;
        client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
    }

    public void SendPaymentRequest(PaymentRequest paymentRequest)
    {
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
                                               | SecurityProtocolType.Tls11
                                               | SecurityProtocolType.Tls12
                                               | SecurityProtocolType.Ssl3;

        //Code throws exception before this callback is called
        ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        };

        var content = new StringContent(JsonConvert.SerializeObject(paymentRequest), Encoding.UTF8, "application/json");

        var response = client.PostAsync("/swish-cpcapi/api/v1/paymentrequests/", content).Result;

        var resultStream = response.Content.ReadAsStreamAsync().Result;
        var result = string.Empty;

        using (var streamReader = new StreamReader(resultStream))
        {
            result = streamReader.ReadToEnd();
        }
    }

}

更新:

在 Chrome 中使用 Postman,我可以先在 Chrome 中导入证书,然后通过商店 Trusted Root Certification Authorities 中的 mmc 发送请求。我还没有设法在代码中找到解决方案。 PS:应用程序的托管要求证书是从文件中加载的,而不是从证书存储中获取的。

更新 2:

带有堆栈跟踪的系统诊断日志:

https://pastebin.com/qMz6X6yJ

【问题讨论】:

    标签: c# ssl


    【解决方案1】:

    发现在服务器上执行了 SSL 测试:

    https://www.ssllabs.com/ssltest/analyze.html?d=mss.swicpc.bankgirot.se

    从这里我可以看到允许以下协议:

    设置后一切正常:

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
    

    【讨论】:

      【解决方案2】:

      您可以像这样将 eventHandler 附加到ServicePointManager

      ServicePointManager.ServerCertificateValidationCallback = ForcedAuthDelegate;
      

      ForcedAuthDelegate 的实现应该返回true 以接受连接:

              static bool ForcedAuthDelegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
              {
                  return true;
              }
      

      【讨论】:

      • 不,代码在此之前抛出异常。如果您查看我的代码,您会发现我已经尝试过了。 ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-05
      • 2018-04-22
      • 2012-10-30
      相关资源
      最近更新 更多