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


103

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

我从.NET的早期版本中看到了此代码。我想我只需要这样的东西。

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

Answers:


28

.Net Core不支持ServicePointManager.ServerCertificateValidationCallback。

当前的情况是它将是 即将到来的4.1。* System.Net.Http合约(HttpClient)的新ServerCertificateCustomValidationCallback方法。.NET Core团队现在正在最终确定4.1合同。您可以在github上的此处阅读有关内容

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

Github上的当前WinHttpHandler.ServerCertificateCustomValidationCallback定义


8
这仅适用于Windows。您是否有针对Linux的解决方案?谢谢。
弗拉基米尔

145

更新:

如下所述,并非所有实现都支持此回调(即,像iOS这样的平台)。如文档所述,在这种情况下,您可以显式设置验证器:

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对它使用工厂模式,因为它是一个共享对象,可能不会立即被丢弃,因此连接将保持打开状态


3
我正在使用.Net Core 1.0,这对我有用。作为一个提示,.Net Core 2.0似乎添加了一个HttpClient名为的属性DangerousAcceptAnyServerCertificateValidator,该属性提供了一种在MacOSX上实现此功能的方法。更多信息在这里-github.com/dotnet/corefx/pull/19908
Troy Witthoeft

1
通过与AWS Lambda一起使用,.NET Core 1.0纠正了阻止我使用自定义根CA证书连接到内部HTTPS的问题。
QuickNull

任何 factory patternHttpClient
Kiquenet

@Kiquenet只需创建一个工厂,GetHttpClient方法将返回配置 的工厂,并在-block中HttpClient使用它using
LuckyLikey

这应该是公认的答案,尤其是因为可以将其范围限定为单个客户端使用。
BinaryPatrick

36

我用这个解决:

启动文件

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);

32

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

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

全局所有证书和AppDomain?
Kiquenet

@Kiquenet:我相信,是的。在其他地方检查更新的答案,现在可能会有更好的解决方案。已经一年了 我想您可以将身份验证器子类化。不,我不知道HttpClient的本地工厂。如果需要更多功能,请查看RestClient。
Troels Larsen

HttpClient(.NET Core 3.1)中没有ClientCredentials属性。
Павле

@Павле:我尚未将此项目更新到3.1,但是应该有这样的属性:docs.microsoft.com/en-us/dotnet/api/…
Troels Larsen

@Павле:这个答案不是关于HttpClient而是WCF服务生成的客户端。也为我的ASMX SoapClient工作,非常感谢!
JanZahradník

14

在.NetCore中,您可以在services configure方法中添加以下代码段,我添加了一项检查以确保仅在开发环境中通过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;
              });

1
为什么-ve恰好实现了mvc.net代码中其他人所建议的内容,并且他们在上面得分了,我只是在.netCore代码中说明了相同的实现方式
Sameh,

大概。因为它没有任何解释。为什么要采用这种方法来代替其他方法,应在调用部分(例如mycontroller.cs)中编写什么代码,这可能是解释的一部分。任何官方文件/引用。
Bhanu Chhabra

正如我说的,如果您在线程顶部查看其他评论,没有太大区别,但他们分别获得了18分和81分,
Sameh

1
由于他们添加了支持其答案的文字,请再次阅读准则。可能会对您有帮助,@ moderators可以指出恕我直言的确切问题。
Bhanu Chhabra

8

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

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

幸运的是,证书是使用链生成的。当然,您始终可以忽略此解决方案,而使用上述解决方案。

所以这是我的解决方案:

  1. 我使用Chrome以P7B格式保存了证书。

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

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

    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
  1. 将这些行放入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
  1. 在应用程序中:
    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);
}

4

首先,请勿在生产中使用它

如果您使用的是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);

3

允许所有证书非常强大,但这也很危险。如果您只想允许有效的证书加上某些证书,可以这样进行。

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://stackoverflow.com/a/44140506/3850405

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.