允许使用HttpClient的不受信任的SSL证书

Jam*_*mie 95 .net c# windows-8 windows-runtime

我很难让我的Windows 8应用程序通过SSL与我的测试Web API进行通信.

似乎HttpClient/HttpClientHandler没有提供和选项来忽略WebRequest之类的不受信任的证书使你(尽管以"hacky"方式ServerCertificateValidationCallback).

任何帮助将非常感激!

Bro*_*ski 136

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

ServicePointManager.ServerCertificateValidationCallback +=
    (sender, cert, chain, sslPolicyErrors) => true;
Run Code Online (Sandbox Code Playgroud)

我主要用于单元测试,我希望在我正在进行托管的端点上运行并尝试使用WCF客户端或者HttpClient.

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

  • 不是downvoter,而是ServerCertificateValidationCallback最大的问题之一是它对你的AppDomain来说基本上是全局的.因此,如果您正在编写一个需要调用具有不受信任证书的站点的库并使用此变通方法,那么您将改变整个应用程序的行为,而不仅仅是您的库.此外,人们应该始终小心"盲目回归真实"的方法.它具有严重的安全隐患.它应该读取/*检查提供的参数,然后仔细决定是否*/return true; (29认同)
  • 您不必全局使用ServicePointManager,可以使用`ServicePointManager.GetServicePoint(Uri)`(参见[docs](https://msdn.microsoft.com/en-us/library/c5f0atwd(v = vs.110) ).aspx))获取仅适用于对该URI的调用的服务点.然后,您可以根据该子集设置属性并处理事件. (3认同)
  • 我建议至少过滤一些标准,如发件人 (2认同)
  • 我真的不得不推荐WebRequestHandler选项与全局ServicePointManager. (2认同)

dtb*_*dtb 79

查看WebRequestHandler类及其ServerCertificateValidationCallback属性:

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

    using (var client = new HttpClient(handler))
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的回复,但我已经研究过了 - 它不适用于Windows 8商店应用程序. (5认同)
  • 使用`HttpClientHandler`? (2认同)

cta*_*cke 39

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

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

var client = new HttpClient(handler);
Run Code Online (Sandbox Code Playgroud)

  • 您不必在这里返回 true - 您实际上可以进行自己的验证!就我而言,我有一个全局应用程序,并且某些客户端没有最新的根证书,因此他们无法正确验证 HTTPS - 在这些情况下我只是检查证书指纹。 (3认同)
  • 我认为设置 `ClientCertificateOptions` 属性是没有必要的。该属性与所使用的客户端证书相关,以便服务器可以识别客户端。从文档中“获取或设置一个值,该值指示是否从证书存储中自动选取证书,或者是否允许调用者传递特定的客户端证书。” (https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler.clientcertificateoptions?view=net-7.0) (3认同)

Jak*_*urc 35

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

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

var http = new HttpClient(handler);
var res = http.GetAsync(url);
Run Code Online (Sandbox Code Playgroud)

  • 当发生中间人攻击并且资金被耗尽时,这对 Jakub 来说会很有趣 (4认同)
  • 谢谢 Jakub,我开发了一个连接到银行的程序......但他们仍然向我发送了无效的证书(!!!)。你把我从某些疯狂中拯救出来......我在我的代码中添加了“感谢 Jakub Sturc” (2认同)

dsc*_*üsä 24

或者您可以在命名空间中使用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)) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • HttpClient 在 .NET Standard 或 UWP 中似乎没有这种覆盖。 (2认同)
  • 不要使用“using”模式:https://learn.microsoft.com/en-us/azure/architecture/antipatterns/improper-instantiation (2认同)

Сер*_*гей 16

在ASP.NET Core 项目的Startup.cs中使用它:

public void ConfigureServices(IServiceCollection services)
{
    // other code
    
    services
        .AddHttpClient<IMyService, MyService>(client =>
        {
            client.BaseAddress = new Uri(myConfiguration.BaseUrl);
        })
        .ConfigurePrimaryHttpMessageHandler(() =>
        {
            // Allowing Untrusted SSL Certificates
            var handler = new HttpClientHandler();
            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
            handler.ServerCertificateCustomValidationCallback =
                (httpRequestMessage, cert, cetChain, policyErrors) => true;

            return handler;
        });
}
Run Code Online (Sandbox Code Playgroud)


Ore*_*tny 12

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

Docs在GitHub上:https: //github.com/onovotny/WinRtHttpClientHandler

  • 有没有办法在不使用所有代码的情况下执行此操作?换句话说,您的解决方案的要点是什么? (9认同)

Pau*_*ulB 10

我在此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>();
  }
}
Run Code Online (Sandbox Code Playgroud)


Ore*_*tny 7

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

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

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

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


Ber*_*ard 7

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

using (var httpClient = new HttpClient())
{
 // do something
}
Run Code Online (Sandbox Code Playgroud)

由于IDisposable接口。请不要!

Microsoft告诉您原因:

在这里您可以找到详细的分析幕后情况:https//aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

关于您的SSL问题,并基于https://docs.microsoft.com/zh-CN/azure/architecture/antipatterns/improper-instantiation/#how-to-fix-the-problem

这是您的模式:

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;
  }
 }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不仅仅是关于“线程安全”。我想展示使用“禁用”SSL 验证的 httpclient 的“正确”方式。其他答案“全局”修改证书管理器。 (3认同)