Docker中.NET 8与OpenSSL的SSL握手错误(SSL_ERROR_SSL)问询
Docker中的SSL握手错误:
SSL_ERROR_SSL(.NET 8与OpenSSL环境) 问题描述
在Windows + Visual Studio环境运行.NET 8应用一切正常,但部署到Docker容器后,使用客户端证书发起HTTPS请求时出现错误:
The SSL connection could not be established, see inner exception.
已尝试在Dockerfile中通过update-ca-certificates手动添加证书,但问题仍未解决,需要排查。
Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base USER root RUN apt-get update && apt-get install -y ca-certificates COPY ["InsuranceApi/sosMedecin.crt", "/usr/local/share/ca-certificates/sosMedecin.crt"] RUN update-ca-certificates USER $APP_UID WORKDIR /app EXPOSE 8080 EXPOSE 8081 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["InsuranceApi/InsuranceApi.csproj", "InsuranceApi/"] RUN dotnet restore "./InsuranceApi/InsuranceApi.csproj" COPY . . WORKDIR "/src/InsuranceApi" RUN dotnet build "./InsuranceApi.csproj" -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish ARG BUILD_CONFIGURATION=Release RUN dotnet publish "./InsuranceApi.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . COPY ["InsuranceApi/sosMedecin.pfx", "/app/publish/sosMedecin.pfx"] ENTRYPOINT ["dotnet", "InsuranceApi.dll"]
AuthenticationService.cs
public class AuthenticationService { private readonly CertificateOptions _certificateOptions; private readonly SsoOptions _ssoOptions; public AuthenticationService(IOptions<CertificateOptions> certificateOptions, IOptions<SsoOptions> ssoOptions) { _certificateOptions = certificateOptions.Value; _ssoOptions = ssoOptions.Value; } public async Task<string?> GetSsoToken() { string? ssoToken = null; HttpClientHandler handler = new HttpClientHandler(); try { // Adding client certificate to HttpClientHandler handler.ClientCertificates.Add(new X509Certificate2(_certificateOptions.CertificatePath, _certificateOptions.CertificatePassword)); // Making the HTTP request to get the SSO token using (var client = new HttpClient(handler)) { var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("format", "text"), new KeyValuePair<string, string>("username", _ssoOptions.Username), new KeyValuePair<string, string>("password", _ssoOptions.Password), new KeyValuePair<string, string>("submit", "confirm") }); HttpResponseMessage response = await client.PostAsync(_ssoOptions.SsoTokenUrl, content); // If response contains the SSO token cookie if (response.Headers.Contains("Set-Cookie")) { var cookieHeader = response.Headers .GetValues("Set-Cookie") .FirstOrDefault(c => c.StartsWith("SSOV2")); if (!string.IsNullOrEmpty(cookieHeader)) { ssoToken = cookieHeader.Split(';')[0].Split('=')[1]; } else { throw new ArgumentNullException("Cookie with SSO token was not found."); } } else { throw new ArgumentNullException($"SSO token not found in response.\nResponse: {await response.Content.ReadAsStringAsync()}"); } } } catch (Exception ex) { // Log any errors and inner exceptions Console.WriteLine($"Unexpected error: {ex.Message}"); while (ex.InnerException != null) { Console.WriteLine($"Inner Exception: {ex.InnerException.Message}"); ex = ex.InnerException; } throw; } return ssoToken; } }
排查方向
客户端证书加载验证
- 在Dockerfile的
final阶段添加RUN ls -l /app/publish/,确认sosMedecin.pfx存在且$APP_UID用户有读取权限。 - 修改证书加载代码,添加Linux环境兼容的存储标志:
handler.ClientCertificates.Add(new X509Certificate2( _certificateOptions.CertificatePath, _certificateOptions.CertificatePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable)); - 检查PFX证书是否包含完整证书链,可通过
openssl pkcs12 -in sosMedecin.pfx -info验证。
- 在Dockerfile的
CA证书信任校验
- 确认
sosMedecin.crt是PEM格式,执行openssl x509 -in /usr/local/share/ca-certificates/sosMedecin.crt -text验证格式正确性。 - 检查
/etc/ssl/certs/目录下是否生成了对应证书的哈希链接文件,确认update-ca-certificates执行生效。
- 确认
OpenSSL与.NET兼容性
- 在容器内执行
openssl version,确保版本为1.1.1或更高(.NET 8推荐版本)。 - 添加环境变量
DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0,强制使用旧的HttpClientHandler排查兼容性问题。
- 在容器内执行
SSL握手日志分析
- 设置环境变量
DOTNET_TRACE=1开启调试日志,捕获更详细的InnerException信息,明确是证书信任、客户端证书验证还是协议版本问题。 - 代码中指定TLS版本:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;。
- 设置环境变量
内容的提问来源于stack exchange,提问作者Markiian Hoinets
相关产品推荐
相关产品推荐

