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

我工作的一个项目,需要连接到一个 https 网站。每次连接时,我的代码都会抛出异常,因为该站点的证书来自不受信任的站点。是否有绕过证书签入的方法。Net core http?

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

 ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
172784 次浏览

在.Net 核心中不支持 ServicePointManager.Server證 icateValidationCallback。

目前的情况是 为即将到来的4.1版本提供一个新的 服务器证书定制验证回调方法。* 系统。网。Http 协议(HttpClient)。.NET 核心团队正在敲定4.1合同。你可以在 github 上的这篇文章中读到这一点

您可以尝试 System 的预发布版本。网。Http 4.1通过直接使用 CoreFx 或 MYGET 提要中的源代码: Https://dotnet.myget.org/gallery/dotnet-core

Github 上当前的 服务器证书定制验证回调定义

来这里寻找一个相同问题的答案,但我使用 WCF 的 NET 核心。如果你也处于同样的境地,使用:

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

更新:

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

handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

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

老回答 ,更有控制力,但可能会抛出 PlatformNotSupportedException:

您可以使用如下的匿名回调函数覆盖 HTTP 调用的 SSL cert 检查

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

此外,我建议对 HttpClient使用工厂模式,因为它是一个共享对象,可能不会立即被释放,因此也就是 连接将保持开放

在使用自签名证书和客户端证书授权时,我遇到了同样的问题。NET Core 2.2和 Docker Linux 容器。在我的开发 Windows 机器上,一切都运行良好,但是在 Docker 中,我得到了这样的错误:

异常: 根据验证过程,远程证书无效

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

所以我的解决办法是:

  1. 我在电脑上使用 Chrome 以 P7B格式保存证书。

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

  3. 打开 ca _ bundle. crt 文件并删除所有 Subject 记录,保留一个干净的文件:

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

GetClientSecurities 方法:

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

进去。NetCore,您可以在服务配置方法中添加以下代码片段,我添加了一个检查,以确保我们只通过开发环境中的 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;
});

我用这个解决:

Startup.cs

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

你的服务

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

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

如果您使用 AddHttpClient 来安装 Http 服务,这将是有用的。 我认为这是发展需要,而不是生产需要。在创建有效证书之前,您可以使用这个 Func。

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

允许所有证书是非常强大的,但也可能是危险的。如果您想只允许有效的证书加上一些特定的证书,可以这样做。

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

对于.NET 6,您可以像下面这样配置主 Http 消息处理程序:

services.AddHttpClient<ITodoListService, TodoListService>()
.ConfigurePrimaryHttpMessageHandler(() => {
var handler = new HttpClientHandler();


if (currentEnvironment.IsDevelopment()) {
handler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
}


return handler;
});

链接到官方文件