155

我正在努力让我的 Windows 8 应用程序通过 SSL 与我的测试 Web API 进行通信。

似乎 HttpClient/HttpClientHandler 没有提供忽略不受信任的证书的选项,如 WebRequest 使您能够(尽管以“hacky”方式使用ServerCertificateValidationCallback)。

任何帮助将非常感激!

4

12 回答 12

178

一个快速而肮脏的解决方案是使用ServicePointManager.ServerCertificateValidationCallback委托。这允许您提供自己的证书验证。验证在整个应用程序域中全局应用。

ServicePointManager.ServerCertificateValidationCallback +=
    (sender, cert, chain, sslPolicyErrors) => true;

我主要将其用于单元测试,在我想针对正在托管的端点运行并尝试使用WCF 客户端HttpClient.

对于生产代码,您可能需要更细粒度的控制,最好使用 theWebRequestHandler及其ServerCertificateValidationCallback委托属性(请参阅下面的 dtb 答案)。或ctacke使用. HttpClientHandler我现在更喜欢这两个中的任何一个,即使我的集成​​测试胜过我过去的做法,除非我找不到任何其他钩子。

于 2013-08-14T12:39:25.617 回答
115

如果您尝试在 .NET Standard 库中执行此操作,这里有一个简单的解决方案,其中存在仅true在处理程序中返回的所有风险。我把安全留给你。

var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ServerCertificateCustomValidationCallback = 
    (httpRequestMessage, cert, cetChain, policyErrors) =>
{
    return true;
};

var client = new HttpClient(handler);
于 2017-10-08T01:59:40.833 回答
100

查看WebRequestHandler 类及其ServerCertificateValidationCallback 属性

using (var handler = new WebRequestHandler())
{
    handler.ServerCertificateValidationCallback = ...

    using (var client = new HttpClient(handler))
    {
        ...
    }
}
于 2012-09-23T16:04:52.390 回答
44

如果您使用的是System.Net.Http.HttpClient我相信正确的模式是

var handler = new HttpClientHandler() 
{ 
    ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};

var http = new HttpClient(handler);
var res = http.GetAsync(url);

链接到官方文档

于 2019-10-29T10:41:00.567 回答
26

或者您可以在命名空间中使用HttpClientWindows.Web.Http

var filter = new HttpBaseProtocolFilter();
#if DEBUG
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
#endif
using (var httpClient = new HttpClient(filter)) {
    ...
}
于 2015-02-27T10:39:54.003 回答
18

这里的大多数答案都建议使用典型模式:

using (var httpClient = new HttpClient())
{
 // do something
}

因为 IDisposable 接口。请不要!

微软告诉你原因:

在这里您可以找到幕后发生的详细分析: 您使用 HttpClient 错误,它正在破坏您的软件

微软官方链接:HttpClient

HttpClient 旨在被实例化一次并在应用程序的整个生命周期中重复使用。为每个请求实例化一个 HttpClient 类将耗尽重负载下可用的套接字数量。这将导致 SocketException 错误。

关于您的 SSL 问题并基于不正确的实例化反模式 # 如何解决问题

这是你的模式:

class HttpInterface
{
 // https://docs.microsoft.com/en-us/azure/architecture/antipatterns/improper-instantiation/#how-to-fix-the-problem
 // https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient#remarks
 private static readonly HttpClient client;

 // static initialize
 static HttpInterface()
 {
  // choose one of these depending on your framework
  
  // HttpClientHandler is an HttpMessageHandler with a common set of properties
  var handler = new HttpClientHandler()
  {
      ServerCertificateCustomValidationCallback = delegate { return true; },
  };
  // derives from HttpClientHandler but adds properties that generally only are available on full .NET
  var handler = new WebRequestHandler()
  {
      ServerCertificateValidationCallback = delegate { return true; },
      ServerCertificateCustomValidationCallback = delegate { return true; },
  };

  client = new HttpClient(handler);
 }
 
 .....
 
 // in your code use the static client to do your stuff
 var jsonEncoded = new StringContent(someJsonString, Encoding.UTF8, "application/json");

 // here in sync
 using (HttpResponseMessage resultMsg = client.PostAsync(someRequestUrl, jsonEncoded).Result)
 {
  using (HttpContent respContent = resultMsg.Content)
  {
   return respContent.ReadAsStringAsync().Result;
  }
 }
}
于 2019-02-15T10:20:48.217 回答
14

在 Windows 8.1 中,您现在可以信任无效的 SSL 证书。您必须使用 Windows.Web.HttpClient,或者如果您想使用 System.Net.Http.HttpClient,您可以使用我写的消息处理程序适配器: http ://www.nuget.org/packages/WinRtHttpClientHandler

文档在 GitHub 上: https ://github.com/onovotny/WinRtHttpClientHandler

于 2013-09-23T02:15:07.643 回答
7

如果这是针对 Windows 运行时应用程序,则必须将自签名证书添加到项目并在 appxmanifest 中引用它。

文档在这里:http: //msdn.microsoft.com/en-us/library/windows/apps/hh465031.aspx

如果它来自不受信任的 CA(例如机器本身不信任的私有 CA),则同样如此——您需要获取 CA 的公共证书,将其作为内容添加到应用程序中,然后将其添加到清单中。

完成后,应用程序会将其视为正确签名的证书。

于 2013-01-04T23:36:21.410 回答
6

我在这个Kubernetes 客户端中找到了一个示例,他们使用X509VerificationFlags.AllowUnknownCertificateAuthority信任自签名自签名根证书。我稍微修改了他们的示例以使用我们自己的 PEM 编码根证书。希望这可以帮助某人。

namespace Utils
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Net.Security;
  using System.Security.Cryptography.X509Certificates;

  /// <summary>
  /// Verifies that specific self signed root certificates are trusted.
  /// </summary>
  public class HttpClientHandler : System.Net.Http.HttpClientHandler
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="HttpClientHandler"/> class.
    /// </summary>
    /// <param name="pemRootCerts">The PEM encoded root certificates to trust.</param>
    public HttpClientHandler(IEnumerable<string> pemRootCerts)
    {
      foreach (var pemRootCert in pemRootCerts)
      {
        var text = pemRootCert.Trim();
        text = text.Replace("-----BEGIN CERTIFICATE-----", string.Empty);
        text = text.Replace("-----END CERTIFICATE-----", string.Empty);
        this.rootCerts.Add(new X509Certificate2(Convert.FromBase64String(text)));
      }

      this.ServerCertificateCustomValidationCallback = this.VerifyServerCertificate;
    }

    private bool VerifyServerCertificate(
      object sender,
      X509Certificate certificate,
      X509Chain chain,
      SslPolicyErrors sslPolicyErrors)
    {
      // If the certificate is a valid, signed certificate, return true.
      if (sslPolicyErrors == SslPolicyErrors.None)
      {
        return true;
      }

      // If there are errors in the certificate chain, look at each error to determine the cause.
      if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0)
      {
        chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

        // add all your extra certificate chain
        foreach (var rootCert in this.rootCerts)
        {
          chain.ChainPolicy.ExtraStore.Add(rootCert);
        }

        chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
        var isValid = chain.Build((X509Certificate2)certificate);

        var rootCertActual = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
        var rootCertExpected = this.rootCerts[this.rootCerts.Count - 1];
        isValid = isValid && rootCertActual.RawData.SequenceEqual(rootCertExpected.RawData);

        return isValid;
      }

      // In all other cases, return false.
      return false;
    }

    private readonly IList<X509Certificate2> rootCerts = new List<X509Certificate2>();
  }
}
于 2019-05-09T10:48:41.240 回答
2

我没有答案,但我有一个选择。

如果您使用Fiddler2监控流量并启用 HTTPS 解密,您的开发环境不会抱怨。这不适用于 WinRT 设备,例如 Microsoft Surface,因为您无法在它们上安装标准应用程序。但是你开发的Win8电脑就可以了。

要在 Fiddler2 中启用 HTTPS 加密,请转到Tools > Fiddler Options > HTTPS (Tab) > Check "Decrypt HTTPS Traffic"

我将密切关注这个线程,希望有人能有一个优雅的解决方案。

于 2013-02-04T23:38:36.850 回答
1

我在网上找到了一个似乎效果很好的例子:

首先你创建一个新的ICertificatePolicy

using System.Security.Cryptography.X509Certificates;
using System.Net;

public class MyPolicy : ICertificatePolicy
{
  public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, 
int certificateProblem)
  {
    //Return True to force the certificate to be accepted.
    return true;
  }
}

然后在发送您的 http 请求之前使用它,如下所示:

System.Net.ServicePointManager.CertificatePolicy = new MyPolicy();

http://www.terminally-incoherent.com/blog/2008/05/05/send-a-https-post-request-with-c/

于 2017-02-24T22:13:55.723 回答
0

对于 Xamarin Android,这是唯一对我有用的解决方案:另一个堆栈溢出帖子

如果您正在使用AndroidClientHandler,则需要提供一个和一个禁用所有检查SSLSocketFactory的自定义实现。HostnameVerifier为此,您需要继承AndroidClientHandler并覆盖适当的方法。

internal class BypassHostnameVerifier : Java.Lang.Object, IHostnameVerifier
{
    public bool Verify(string hostname, ISSLSession session)
    {
        return true;
    }
}
 
internal class InsecureAndroidClientHandler : AndroidClientHandler
{
    protected override SSLSocketFactory ConfigureCustomSSLSocketFactory(HttpsURLConnection connection)
    {
        return SSLCertificateSocketFactory.GetInsecure(1000, null);
    }
 
    protected override IHostnameVerifier GetSSLHostnameVerifier(HttpsURLConnection connection)
    {
        return new BypassHostnameVerifier();
    }
}

进而

var httpClient = new System.Net.Http.HttpClient(new InsecureAndroidClientHandler());
于 2020-12-14T06:14:37.830 回答