.NET 5 部署Ubuntu 20.04后SSL握手失败问题求助
解决.NET 5 + Ubuntu 20.04下HttpWebRequest TLS握手失败问题
我之前帮同事排查过几乎一模一样的场景,结合你给出的所有排查细节,问题核心是.NET 5在Linux下的TLS配置逻辑和.NET Core 3.1有较大差异,再加上Ubuntu 20.04的OpenSSL默认设置,导致SSL握手失败。下面给你几个实测有效的解决方案:
方案1:替换HttpWebRequest为HttpClient并显式控制TLS参数
HttpWebRequest在.NET 5里已经是基于SocketsHttpHandler的封装,直接用HttpClient能更精准控制SSL握手过程。根据你用curl测试成功的TLS 1.2和AES128-SHA256套件,我们可以在代码里显式指定:
using System; using System.Net.Http; using System.Net.Security; using System.Security.Authentication; using System.Threading.Tasks; namespace BugSSL { class Program { static async Task Main(string[] args) { await CurlWithHttpClient("https://www.boe.es/diario_boe/xml.php?id=BOE-S-20201216"); } static async Task CurlWithHttpClient(string url) { try { Console.WriteLine("START-------------------------------------------------"); Console.WriteLine($"Getting URL {url}"); // 匹配curl成功的TLS版本和密码套件 var sslOptions = new SslClientAuthenticationOptions { EnabledSslProtocols = SslProtocols.Tls12, CipherSuitesPolicy = new CipherSuitesPolicy(new[] { TlsCipherSuite.TLS_RSA_WITH_AES_128_SHA256, // 对应你看到的AES128-SHA256 TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TlsCipherSuite.TLS_AES_128_GCM_SHA256 }) }; using var handler = new SocketsHttpHandler { SslOptions = sslOptions }; using var httpClient = new HttpClient(handler); httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("SSLBugTest/0.0.0"); httpClient.DefaultRequestHeaders.AcceptEncoding.ParseAdd("gzip, deflate"); var response = await httpClient.GetAsync(url); response.EnsureSuccessStatusCode(); Console.WriteLine($"Response status: {response.StatusCode} {response.ReasonPhrase}"); Console.WriteLine("Response headers"); foreach (var header in response.Headers) { Console.WriteLine($" {header.Key}: {string.Join(", ", header.Value)}"); } Console.WriteLine($"Content-Type: {response.Content.Headers.ContentType}"); Console.WriteLine("END---------------------------------------------------"); } catch (Exception e) { Console.Error.WriteLine($"Error processing {url}. Error: {e.Message}"); Console.Error.WriteLine(e.StackTrace); while (e.InnerException != null) { e = e.InnerException; Console.WriteLine($"Inner exception: {e.Message}"); Console.Error.WriteLine(e.StackTrace); } } } } }
方案2:确保.NET 5正确读取自定义OpenSSL配置
你设置的OPENSSL_CONF环境变量可能没有被dotnet进程正确加载,试试在启动命令中直接注入环境变量(而不是提前export):
OPENSSL_CONF=/var/www/spider/openssl.cnf dotnet Spider.dll
另外,建议调整自定义openssl.cnf的CipherString,避免排除必要套件:
openssl_conf = openssl_init [openssl_init] ssl_conf = ssl_sect [ssl_sect] system_default = system_default_sect [system_default_sect] MinProtocol = TLSv1.2 CipherString = DEFAULT@SECLEVEL=1:!aNULL:!eNULL:!MD5
方案3:临时回退到旧的HttpClientHandler(应急用)
如果上面的方法都无效,可以强制.NET使用旧的HttpClientHandler(非SocketsHttpHandler),通过环境变量切换:
DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0 dotnet Spider.dll
注意:这个方案只是临时应急,因为SocketsHttpHandler是.NET 5+的默认实现,性能和稳定性更好,长期来看还是建议用方案1适配新的逻辑。
问题根源解析
- .NET 5重构了Linux下的TLS处理逻辑,不再完全继承OpenSSL的系统默认密码套件,而是有自己的优先级排序;
- HttpWebRequest在.NET 5中的底层实现从旧的HttpClientHandler切换到了SocketsHttpHandler,导致相同的OpenSSL配置表现和.NET Core 3.1不一致;
- Ubuntu 20.04的OpenSSL 1.1.1f默认SECLEVEL是2,即使你自定义了配置,.NET 5可能没有正确加载,导致密码套件协商时被对方服务器拒绝。
内容的提问来源于stack exchange,提问作者Sourcerer
相关产品推荐
相关产品推荐

