如何解决linux 上的 ASP.NET CORE 5.0 TLS 1.2 问题,但在 asp.net core 3.1 上正在运行
我在 asp.net core 5.0 和 linux 中遇到了 TLS 1.2 的问题。 它仅在 asp.net core 5.0 中发生,同样的代码在 asp.net core 3.1 上运行
使用 HttpClient 和 net5.0 在 Ubuntu 18.04/20.04 上使用 OpenSSL 的 SSL 握手失败
System.Net.Http.HttpRequestException: The SSL connection Could not be established,see inner exception.
---> System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
at System.Net.Security.SslStream.<FillHandshakeBufferAsync>g__InternalFillHandshakeBufferAsync|182_0[TIOAdapter](TIOAdapter adap,ValueTask`1 task,Int32 minSize)
at System.Net.Security.SslStream.ReceiveBlobAsync[TIOAdapter](TIOAdapter adapter)
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter,Boolean receiveFirst,Byte[] reAuthenticationData,Boolean isApm)
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async,Stream stream,SslClientAuthenticationoptions sslOptions,CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async,CancellationToken cancellationToken)
at System.Net.Http.httpconnectionPool.ConnectAsync(HttpRequestMessage request,Boolean async,CancellationToken cancellationToken)
at System.Net.Http.httpconnectionPool.GetHttp2ConnectionAsync(HttpRequestMessage request,CancellationToken cancellationToken)
at System.Net.Http.httpconnectionPool.SendWithRetryAsync(HttpRequestMessage request,Boolean doRequestAuth,CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
at System.Net.Http.DecompressionHandler.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request,HttpCompletionoption completionoption,Boolean emitTelemetryStartStop,CancellationToken cancellationToken)
我正在分享一个控制台应用程序,您应该查看它以了解此问题。 不幸的是,我无法共享应用程序的凭据,并且由于 nda 的原因,使用其 api 的提供者也无法共享。我们还在防火墙上将我们的 ip 列入白名单。 但我分享了代码,所以你可以看到我尝试过的一切
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Test
{
class Program
{
static async Task<int> Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext,services) =>
{
services.AddHttpClient("configured-certificate")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new httpclienthandler()
{
CheckCertificateRevocationList = false,UseDefaultCredentials = false,ClientCertificateOptions = ClientCertificateOption.Manual,SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11,ServerCertificateCustomValidationCallback = (message,cert,chain,errors) => ServerCertificateCustomValidation(message,errors),AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,//ServerCertificateCustomValidationCallback = httpclienthandler.DangerousAcceptAnyServerCertificateValidator,//ServerCertificateCustomValidationCallback = delegate { return true; },CookieContainer = new CookieContainer()
};
});
services.AddTransient<ITestService,TestService>();
services.AddLogging((configure) =>
{
configure.AddConsole();
configure.AddDebug();
});
var env = hostContext.HostingEnvironment;
Console.Write($"Environtment: {env.EnvironmentName}\n");
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json",optional: true,reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json",optional: true)
.AddEnvironmentvariables();
hostContext.Configuration = configurationBuilder.Build();
})
.UseConsoleLifetime();
var host = builder.Build();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback +=
(sender,certificate,errors) =>
{
return true;
};
try
{
var myService = host.Services.GetrequiredService<ITestService>();
var pageContent = await myService.GetPage();
Console.WriteLine(pageContent);
}
catch (Exception ex)
{
var logger = host.Services.GetrequiredService<ILogger<Program>>();
logger.LogError(ex,"An error occurred.");
}
return 0;
}
private static bool ServerCertificateCustomValidation(HttpRequestMessage requestMessage,X509Certificate2 certificate,X509Chain chain,SslPolicyErrors sslErrors)
{
//It is possible inpect the certificate provided by server
Console.WriteLine($"Requested URI: {requestMessage.RequestUri}");
Console.WriteLine($"Effective date: {certificate.GetEffectiveDateString()}");
Console.WriteLine($"Exp date: {certificate.GetExpirationDateString()}");
Console.WriteLine($"Issuer: {certificate.Issuer}");
Console.WriteLine($"Subject: {certificate.Subject}");
//Based on the custom logic it is possible to decide whether the client considers certificate valid or not
Console.WriteLine($"Errors: {sslErrors}");
return true;
//return sslErrors == SslPolicyErrors.None;
}
}
public interface ITestService
{
Task<string> GetPage();
}
public class TestService : ITestService
{
private readonly IHttpClientFactory _clientFactory;
public TestService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<string> GetPage()
{
var uri = "https://secureuri";
var client = _clientFactory.CreateClient("configured-certificate");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic","fglsdhjgoñisdjfhgoishdfg=");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("br"));
var xml = System.IO.File.ReadAllText("request.xml");
var data = new StringContent(xml,Encoding.UTF8,"application/xml");
var response = await client.PostAsync(uri,data);
if (response.IsSuccessstatusCode)
{
return await response.Content.ReadAsstringAsync();
}
else
{
return $"StatusCode: {response.StatusCode}";
}
}
}
}
发布配置文件如下:
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project Toolsversion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any cpu</Platform>
<PublishDir>D:\Test</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net5.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
</PropertyGroup>
</Project>
我在 asp.net core 3 和 curl 上有结果
root@skynet:# curl -u user:passwd -kv https://xmldirect.ehi.com/services30/OTA30SOAP
* Trying 12.43.130.115:443...
* TCP_NODELAY set
* Connected to xmldirect.ehi.com (12.43.130.115) port 443 (#0)
* ALPN,offering h2
* ALPN,offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT),TLS handshake,Client hello (1):
* TLSv1.3 (IN),Server hello (2):
* TLSv1.2 (IN),Certificate (11):
* TLSv1.2 (IN),Server finished (14):
* TLSv1.2 (OUT),Client key exchange (16):
* TLSv1.2 (OUT),TLS change cipher,Change cipher spec (1):
* TLSv1.2 (OUT),Finished (20):
* TLSv1.2 (IN),Finished (20):
* SSL connection using TLSv1.2 / AES256-GCM-SHA384
* ALPN,server accepted to use http/1.1
* Server certificate:
* subject: C=US; postalCode=63105; ST=Missouri; L=St. Louis; street=600 Corporate Park Dr.; O=Enterprise Holdings Inc.; CN=xmldirect.ehi.com
* start date: Mar 12 00:00:00 2020 GMT
* expire date: Mar 12 23:59:59 2022 GMT
* issuer: C=GB; ST=Greater Manchester; L=Salford; O=COModo CA Limited; CN=COModo RSA Organization Validation Secure Server CA
* SSL certificate verify ok.
* Server auth using Basic with user 'user'
> GET /services30/OTA30SOAP HTTP/1.1
> Host: xmldirect.ehi.com
> Authorization: Basic fglsdhjgoñisdjfhgoishdfg=
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Mon,05 Jul 2021 23:58:48 GMT
< Server: Apache
< Content-Length: 0
< Content-Type: application/xml
< vary: Accept-Encoding
生活环境
distributor ID: Ubuntu
Description: Ubuntu 18.04.5 LTS
Release: 18.04
Codename: bionic
OpenSSL> version
OpenSSL 1.0.2s 28 May 2019
测试环境
distributor ID: Ubuntu
Description: Ubuntu 20.04.2 LTS
Release: 20.04
Codename: focal
OpenSSL> version
OpenSSL 1.1.1f 31 Mar 2020
客户端 Hello 上的 Asp.net 核心 3.1 密码(28 个套件)
客户端 Hello 上的 Asp.net 核心 5.0 密码(9 个套件)
https://github.com/dotnet/runtime/issues/55227
在好的情况下,客户端提供一堆密码,服务器将选择密码套件:TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)(数据包 6 -> ServerHello) 在 5.0 中,默认密码仅限于目前被认为是强大且安全的密码。上面那个不在列表中
解决方法
我解决了这个问题 https://askubuntu.com/questions/1233186/ubuntu-20-04-how-to-set-lower-ssl-security-level 和 https://github.com/dotnet/runtime/issues/45244
我在/etc/ssl/openssl.cnf中修改了以下内容
- 在 oid 部分下方添加系统默认部分
# Extra OBJECT IDENTIFIER info:
#oid_file = $ENV::HOME/.oid
oid_section = new_oids
# System default
openssl_conf = default_conf
- 在文件末尾添加默认部分
[default_conf]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT:@SECLEVEL=1
#CipherString = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-S>
#CipherString = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-S>
从 https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=old&openssl=1.1.1d&guideline=5.6 生成的 CipherString 对我不起作用
但以下工作正常 CipherString = DEFAULT:@SECLEVEL=1
最后要检查的是 openssl.cnf 的路径,因为在我的情况下,当我放置 Ubuntu 18.04 时:
openssl 版本 -d OPENSSLDIR: "/usr/lib/ssl"
的openssl.cnfmv /usr/local/ssl/openssl.cnf /usr/local/ssl/openssl.cnf.bak ln -s /usr/local/ssl/openssl.cnf /etc/ssl/openssl.cnf
重新启动api或应用程序以查看更改非常重要
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。