Issue—C#—ssl相关错误

报错:

.net 6 :

{

"MessageTemplate": "An unhandled exception has occurred while executing the request."

"Exception": "System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.\r\n ---> System.Security.Authentication.AuthenticationException: Authentication failed because the remote party sent a TLS alert: 'HandshakeFailure'.\r\n ---> System.ComponentModel.Win32Exception (0x80090326): 接收到的消息异常,或格式不正确。\r\n --- End of inner exception stack trace ---\r\n at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)\r\n at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)\r\n --- End of inner exception stack trace ---\r\n at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request)\r\n at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)\r\n at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpClient.g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)\r\n at Oxlias.Validation.ZhxtTokenAuthenticationHandler.GetZhxtTokenData(String uri, HttpMethod httpmethod, String zhxttoken)\r\n at Oxlias.Validation.ZhxtTokenAuthenticationHandler.AuthenticateAsync()\r\n at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)\r\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)\r\n at Hellang.Middleware.ProblemDetails.ProblemDetailsMiddleware.Invoke(HttpContext context)"

}

.net framework 4.6.2 :未能创建 SSL/TLS 安全通道。终止连接。


一、通过代码解决

这种只适合Client与Server双方服务器的TLS协议版本号兼容,还需要Cipher Suites(密码套件)兼容的前提下。

  1. httpclient写法

Product

Versions

.NET

Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7

.NET Framework

4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1

.NET Standard

1.1, 1.2, 1.3, 1.4, 1.6, 2.0, 2.1

UWP

10.0

Xamarin.iOS

10.8

Xamarin.Mac

3.0

private async Task GetZhxtTokenData(string uri)
{
    //HttpClientHandler clientHandler = new HttpClientHandler();
    //clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
    //clientHandler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls13 | System.Security.Authentication.SslProtocols.Tls11;

    //HttpClient client = new HttpClient(clientHandler);
    //var request = new HttpRequestMessage
    //{
    //    Method = httpmethod,
    //    RequestUri = new(uri, UriKind.Absolute)
    //};
    //request.Headers.Add("Authorization", zhxttoken);
    //var gettoken_Response = await client.SendAsync(request);
    
    //return await gettoken_Response.Content.ReadAsStringAsync();
    using (var clientHandler = new HttpClientHandler())
    {
        clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
        clientHandler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls13 | System.Security.Authentication.SslProtocols.Tls11;
        using (var httpClient = new HttpClient(clientHandler))
        {
            httpClient.DefaultRequestHeaders.Add("Authorization", "123");
            using (var response = await httpClient.GetAsync(uri))
            {
                if (response.StatusCode == HttpStatusCode.RequestTimeout)
                {
                    return HttpStatusCode.RequestTimeout.ToString();
                }
                return await response.Content.ReadAsStringAsync();
            }
        }
    }
}
  1. HttpWebRequest写法

public static string GetZhxtTokenData_HttpWebRequest(string PostUrl, string Parameters, string zhxttoken)
        {
            string content = string.Empty;
            try
            {
                //ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Ssl3;    //https 请求必需语句,http 请求可省略
                //跳过ssl验证
                ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
                //path不是登录界面,是登录界面向服务器提交数据的界面
                HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(PostUrl);
                myReq.Method = "get";
                //myReq.ContentType = "application/json";
                //myReq.Connection = "keep-alive";
                myReq.Headers.Add("Cookie", "477cadb5a1f917cda5f5d9cab20f8841=42c7f20d7a509babe62c3e74995d5140; 3c343960f5dd4584c34cd6b38885cefe=000e1bf2bbd8e5ae2dabff0eb27e3b6f");
                //myReq.Headers.Add("usercode", "JRFZCX_MYFK");
                //myReq.Headers.Add("password", "*&ZHY&*0379");//&JRFZ&01
                myReq.Headers.Add("Authorization", zhxttoken);
                //填充POST数据
                if (Parameters != null)
                {
                    //转换为字节数组
                    byte[] bytesRequestData = Encoding.UTF8.GetBytes(Parameters);
                    myReq.ContentLength = bytesRequestData.Length;
                    Stream requestStream = myReq.GetRequestStream();
                    requestStream.Write(bytesRequestData, 0, bytesRequestData.Length);
                    requestStream.Close();
                }
                else
                {
                    myReq.ContentLength = 0;
                }

                //发送POST数据请求服务器
                HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
                //获取服务器返回信息
                Stream myStream = HttpWResp.GetResponseStream();
                StreamReader reader = new StreamReader(myStream, Encoding.UTF8);
                content = reader.ReadToEnd();
                reader.Close();
                HttpWResp.Close();
            }
            catch (Exception ex)
            {
                content = ex.ToString();
            }
            return content;
        }

二、通过服务期配置解决

1.Analysis

当通过代码手段无法解决时需从问题根源寻找解决办法。

根据错误提示“System.Security.Authentication.AuthenticationException: Authentication failed because the remote party sent a TLS alert: 'HandshakeFailure'. System.ComponentModel.Win32Exception (0x80090326): 接收到的消息异常,或格式不正确。”分析出应该是两个服务器TLS版本号不兼容导致两边通信建立连接时三次握手失败。

①经查看服务器A(Red hat8.1-5) ssl密码件如下:

sh-4.4$ cat DEFAULT.pol 
# A reasonable default for today's standards. It should provide
# 112-bit security with the exception of SHA1 signatures needed for DNSSec
# and other still prevalent legacy use of SHA1 signatures.

# MACs: all HMAC with SHA1 or better + all modern MACs (Poly1305 etc)
# Curves: all prime >= 255 bits (including Bernstein curves)
# Signature algorithms: with SHA-1 hash or better (no DSA)
# TLS Ciphers: >= 128-bit key, >= 128-bit block (AES, ChaCha20, including AES-CBC)
# non-TLS Ciphers: as TLS Ciphers with added Camellia
# key exchange: ECDHE, RSA, DHE (no DHE-DSS)
# DH params size: >= 2048
# RSA params size: >= 2048
# TLS protocols: TLS >= 1.2, DTLS >= 1.2

mac = AEAD HMAC-SHA2-256 HMAC-SHA1 UMAC-128 HMAC-SHA2-384 HMAC-SHA2-512

group = X25519 X448 SECP256R1 SECP384R1 SECP521R1 \
    FFDHE-2048 FFDHE-3072 FFDHE-4096 FFDHE-6144 FFDHE-8192

hash = SHA2-256 SHA2-384 SHA2-512 SHA3-256 SHA3-384 SHA3-512 SHA2-224 SHA1

sign = ECDSA-SHA3-256 ECDSA-SHA2-256 \
       ECDSA-SHA3-384 ECDSA-SHA2-384 \
       ECDSA-SHA3-512 ECDSA-SHA2-512 \
       EDDSA-ED25519 EDDSA-ED448 \
       RSA-PSS-SHA2-256 RSA-PSS-SHA2-384 RSA-PSS-SHA2-512 \
       RSA-SHA3-256 RSA-SHA2-256 \
       RSA-SHA3-384 RSA-SHA2-384 \
       RSA-SHA3-512 RSA-SHA2-512 \
       ECDSA-SHA2-224 RSA-PSS-SHA2-224 RSA-SHA2-224 \
       ECDSA-SHA1 RSA-PSS-SHA1 RSA-SHA1

tls_cipher = AES-256-GCM AES-256-CCM CHACHA20-POLY1305 AES-256-CBC \
    AES-128-GCM AES-128-CCM AES-128-CBC

cipher = AES-256-GCM AES-256-CCM CHACHA20-POLY1305 CAMELLIA-256-GCM \
    AES-256-CTR AES-256-CBC CAMELLIA-256-CBC AES-128-GCM AES-128-CCM \
    CAMELLIA-128-GCM AES-128-CTR AES-128-CBC CAMELLIA-128-CBC

# 'RSA' is intentionally before DHE ciphersuites, as the DHE ciphersuites have
# interoperability issues in TLS.
key_exchange = ECDHE RSA DHE DHE-RSA PSK DHE-PSK ECDHE-PSK ECDHE-GSS DHE-GSS

protocol = TLS1.3 TLS1.2 DTLS1.2
ike_protocol = IKEv2

min_tls_version = TLS1.2
min_dtls_version = DTLS1.2

# Parameter sizes
mi

支持TLS1.2,也支持TLS1.3.

请求该服务器的网址显示的是TLS1.3,但另一台仅支持TLS1.2的服务器发来的请求依然可以成功创建连接并通信。

②经查看服务器B(Windows server 2012 r2) ssl密码件如下:

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P521
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P521
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P521
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P521
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P521
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_NULL_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA

2.solution

这个错误有些人说是请求TLS1.3的服务必须是由支持TLS1.3的客户端才能成功建立连接是不正确的。详细要看TLS1.3的服务所在的服务器是否支持TLS1.2,如果支持,只需要保证两台服务器密码套件兼容就可以成功建立连接。

我解决此错误的办法:

将服务器B密码套件修改为默认后,再次通信即解决问题。

Final、Supplementary htpps knowledge

参考链接

1、关于HTTP、HTTPS、TLS的关系:HTTPS连接是由HTTP协议与TLS协议共同完成。

Issue—C#—ssl相关错误_第1张图片

2、建立HTTPS连接不仅需要Client与Server双方的TLS协议版本号兼容,还需要Cipher Suites(密码套件)兼容。关于什么是Cipher Suites可以自行查阅资料,本文不详细展开说明。Cipher Suites的样子如图所示:

Issue—C#—ssl相关错误_第2张图片

你可能感兴趣的:(C#,Windows,Linux,c#,https)