绕过 .net 核心中的无效 SSL 证书

Posted

技术标签:

【中文标题】绕过 .net 核心中的无效 SSL 证书【英文标题】:bypass invalid SSL certificate in .net core 【发布时间】:2016-11-03 11:37:43 【问题描述】:

我正在做一个需要连接到 https 站点的项目。每次连接时,我的代码都会抛出异常,因为该站点的证书来自不受信任的站点。有没有办法绕过 .net core http 中的证书检查?

我在以前版本的 .NET 中看到了这段代码。我想我只需要这样的东西。

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

【问题讨论】:

Allowing Untrusted SSL Certificates with HttpClient的可能重复 如果阅读此问答的人试图忽略客户端 SignalR 集线器连接的 SSL 验证,请参阅此处 - ***.com/a/59835125/1549918。 【参考方案1】:

.Net Core 不支持 ServicePointManager.ServerCertificateValidationCallback。

目前的情况是,这将是一个 即将推出的 4.1.* System.Net.Http 合约 (HttpClient) 的新 ServerCertificateCustomValidationCallback 方法。 .NET Core 团队现在正在敲定 4.1 合同。您可以在here on github 阅读有关此内容的信息

您可以直接在 CoreFx 或 MYGET 提要中使用源代码来试用 System.Net.Http 4.1 的预发布版本: https://dotnet.myget.org/gallery/dotnet-core

Github 上当前的 WinHttpHandler.ServerCertificateCustomValidationCallback 定义

【讨论】:

这仅适用于 Windows。你有 Linux 的解决方案吗?谢谢。【参考方案2】:

来到这里寻找相同问题的答案,但我正在使用 WCF for NET Core。如果您在同一条船上,请使用:

client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = 
    new X509ServiceCertificateAuthentication()
    
        CertificateValidationMode = X509CertificateValidationMode.None,
        RevocationMode = X509RevocationMode.NoCheck
    ;

【讨论】:

全球所有证书和 AppDomain ? @Kiquenet:我相信是的。检查其他地方的更新答案,现在可能有更好的解决方案。已经一年了。如果没有别的,我想你可以将身份验证器子类化。不,我知道没有 HttpClient 的本地工厂。如果您需要更多功能,请查看 RestClient。 HttpClient (.NET Core 3.1) 中没有 ClientCredentials 属性。 @Павле:我还没有把这个项目更新到3.1,但是应该有这样一个属性:docs.microsoft.com/en-us/dotnet/api/…。 @Павле:这个答案不是关于 HttpClient 而是 WCF 服务生成的客户端。也为我的 ASMX SoapClient 工作,非常感谢!【参考方案3】:

更新:

如下所述,并非所有实现都支持此回调(即 ios 等平台)。在这种情况下,正如docs 所说,您可以显式设置验证器:

handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

这也适用于 .NET Core 2.2、3.0 和 3.1

旧答案,有更多控制权但可能会抛出PlatformNotSupportedException

您可以使用这样的匿名回调函数覆盖 HTTP 调用上的 SSL 证书检查

using (var httpClientHandler = new HttpClientHandler())

   httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>  return true; ;
   using (var client = new HttpClient(httpClientHandler))
   
       // Make your request...
   

另外,我建议对HttpClient 使用工厂模式,因为它是一个共享对象,可能不会立即释放,因此connections will stay open。

【讨论】:

我正在使用 .Net Core 1.0,这对我有用。提醒一下,.Net Core 2.0 似乎添加了一个名为 DangerousAcceptAnyServerCertificateValidatorHttpClient 属性,它提供了一种使其在 MacOSX 上工作的方法。更多信息在这里 - github.com/dotnet/corefx/pull/19908 将它与 AWS Lambda 一起使用,.NET Core 1.0 纠正了阻止我使用自定义根 CA 证书连接到内部 HTTPS 的问题。 对于HttpClient 的任何factory pattern @Kiquenet 只需创建一个工厂,其中GetHttpClient 方法返回配置的HttpClient 并在using-block 中使用它。 这应该是公认的答案,尤其是因为它可以被限定为单个客户端使用。【参考方案4】:

在 .NET Core 2.2 和 Docker Linux 容器上使用自签名证书和客户端证书身份验证时,我遇到了同样的问题。在我的开发 Windows 机器上一切正常,但在 Docker 中出现这样的错误:

System.Security.Authentication.AuthenticationException:根据验证程序,远程证书无效

幸运的是,证书是使用链生成的。 当然,你可以随时忽略这个解决方案,使用上面的解决方案。

所以这是我的解决方案:

    我使用 Chrome 以 P7B 格式将证书保存在我的计算机上。

    使用以下命令将证书转换为 PEM 格式:openssl pkcs7 -inform DER -outform PEM -in <cert>.p7b -print_certs > ca_bundle.crt

    打开 ca_bundle.crt 文件并删除所有主题记录,留下一个干净的文件。下面的例子:

    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    将这些行放入 Dockerfile(在最后的步骤中):
    # Update system and install curl and ca-certificates
    RUN apt-get update && apt-get install -y curl && apt-get install -y ca-certificates
    # Copy your bundle file to the system trusted storage
    COPY ./ca_bundle.crt /usr/local/share/ca-certificates/ca_bundle.crt
    # During docker build, after this line you will get such output: 1 added, 0 removed; done.
    RUN update-ca-certificates
    在应用中:
    var address = new EndpointAddress("https://serviceUrl");                
    var binding = new BasicHttpsBinding
    
        CloseTimeout = new TimeSpan(0, 1, 0),
        OpenTimeout = new TimeSpan(0, 1, 0),
        ReceiveTimeout = new TimeSpan(0, 1, 0),
        SendTimeout = new TimeSpan(0, 1, 0),
        MaxBufferPoolSize = 524288,
        MaxBufferSize = 65536,
        MaxReceivedMessageSize = 65536,
        TextEncoding = Encoding.UTF8,
        TransferMode = TransferMode.Buffered,
        UseDefaultWebProxy = true,
        AllowCookies = false,
        BypassProxyOnLocal = false,
        ReaderQuotas = XmlDictionaryReaderQuotas.Max,
        Security =
        
            Mode = BasicHttpsSecurityMode.Transport,
            Transport = new HttpTransportSecurity
            
                ClientCredentialType = HttpClientCredentialType.Certificate,
                ProxyCredentialType = HttpProxyCredentialType.None
            
        
    ;
    var client = new MyWSClient(binding, address);
    client.ClientCredentials.ClientCertificate.Certificate = GetClientCertificate("clientCert.pfx", "passwordForClientCert");
    // Client certs must be installed
    client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication
    
        CertificateValidationMode = X509CertificateValidationMode.ChainTrust,
        TrustedStoreLocation = StoreLocation.LocalMachine,
        RevocationMode = X509RevocationMode.NoCheck
    ;

GetClientCertificate 方法:

private static X509Certificate2 GetClientCertificate(string clientCertName, string password)

    //Create X509Certificate2 object from .pfx file
    byte[] rawData = null;
    using (var f = new FileStream(Path.Combine(AppContext.BaseDirectory, clientCertName), FileMode.Open, FileAccess.Read))
    
        var size = (int)f.Length;
        var rawData = new byte[size];
        f.Read(rawData, 0, size);
        f.Close();
    
    return new X509Certificate2(rawData, password);

【讨论】:

【参考方案5】:

在.NetCore中,你可以在服务配置方法中添加以下代码sn-p,我添加了一个检查以确保我们只在开发环境中绕过SSL证书

services.AddHttpClient("HttpClientName", client => 
// code to configure headers etc..
).ConfigurePrimaryHttpMessageHandler(() => 
                  var handler = new HttpClientHandler();
                  if (hostingEnvironment.IsDevelopment())
                  
                      handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>  return true; ;
                  
                  return handler;
              );

【讨论】:

为什么是-ve,这正是其他人在 mvc.net 代码中建议的实现,他们在上面得分,我只是在 .netCore 代码中说明相同的实现 可能。因为它缺乏任何解释。为什么这种方法应该取代任何其他方法,应该在调用部分(比如 mycontroller.cs)中编写什么代码,这可能是解释的一部分。任何官方文件/引用。 正如我所说,如果您查看线程顶部的其他 cmets,则没有太大区别,但他们分别获得 18 分和 81 分, 因为他们添加了支持他们答案的文本,请再次阅读指南。可能会对您有所帮助,@moderators 可以指出确切的问题恕我直言。【参考方案6】:

我解决了这个问题:

Startup.cs

public void ConfigureServices(IServiceCollection services)
    
        services.AddHttpClient("HttpClientWithSSLUntrusted").ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        
            ClientCertificateOptions = ClientCertificateOption.Manual,
            ServerCertificateCustomValidationCallback =
            (httpRequestMessage, cert, cetChain, policyErrors) =>
            
                return true;
            
        );

YourService.cs

public UserService(IHttpClientFactory clientFactory, IOptions<AppSettings> appSettings)
    
        _appSettings = appSettings.Value;
        _clientFactory = clientFactory;
    

var request = new HttpRequestMessage(...

var client = _clientFactory.CreateClient("HttpClientWithSSLUntrusted");

HttpResponseMessage response = await client.SendAsync(request);

【讨论】:

你是救生员!【参考方案7】:

首先,不要在生产中使用它

如果您正在使用 AddHttpClient 中间件,这将很有用。 我认为它是开发目的而不是生产所需要的。在您创建有效证书之前,您可以使用此功能。

Func<HttpMessageHandler> configureHandler = () =>
        
            var bypassCertValidation = Configuration.GetValue<bool>("BypassRemoteCertificateValidation");
            var handler = new HttpClientHandler();
            //!DO NOT DO IT IN PRODUCTION!! GO AND CREATE VALID CERTIFICATE!
            if (bypassCertValidation)
            
                handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, x509Certificate2, x509Chain, sslPolicyErrors) =>
                
                    return true;
                ;
            
            return handler;
        ;

并像这样应用它

services.AddHttpClient<IMyClient, MyClient>(x =>  x.BaseAddress = new Uri("https://localhost:5005"); )
        .ConfigurePrimaryHttpMessageHandler(configureHandler);

【讨论】:

【参考方案8】:

允许所有证书非常强大,但也可能很危险。如果您只想允许有效证书和某些特定证书,可以这样做。

using (var httpClientHandler = new HttpClientHandler())

    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => 
        if (sslPolicyErrors == SslPolicyErrors.None)
        
            return true;   //Is valid
        

        if (cert.GetCertHashString() == "99E92D8447AEF30483B1D7527812C9B7B3A915A7")
        
            return true;
        
        return false;
    ;
    using (var httpClient = new HttpClient(httpClientHandler))
    
        var httpResponse = httpClient.GetAsync("https://example.com").Result;
    

原文出处:

https://***.com/a/44140506/3850405

【讨论】:

以上是关于绕过 .net 核心中的无效 SSL 证书的主要内容,如果未能解决你的问题,请参考以下文章

java HttpsURLConnection怎么绕过证书,原理是啥

gdc服务器ssl证书丢失什么意思

haproxy服务器本身只提供代理,没有ssl证书吗?

HttpClient配置SSL绕过https证书

服务器如何更新ssl证书

windows服务器怎么安装ssl证书