报错:
.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.
}
.net framework 4.6.2 :未能创建 SSL/TLS 安全通道。终止连接。
这种只适合Client与Server双方服务器的TLS协议版本号兼容,还需要Cipher Suites(密码套件)兼容的前提下。
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();
}
}
}
}
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;
}
当通过代码手段无法解决时需从问题根源寻找解决办法。
根据错误提示“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
这个错误有些人说是请求TLS1.3的服务必须是由支持TLS1.3的客户端才能成功建立连接是不正确的。详细要看TLS1.3的服务所在的服务器是否支持TLS1.2,如果支持,只需要保证两台服务器密码套件兼容就可以成功建立连接。
我解决此错误的办法:
将服务器B密码套件修改为默认后,再次通信即解决问题。
参考链接
1、关于HTTP、HTTPS、TLS的关系:HTTPS连接是由HTTP协议与TLS协议共同完成。
2、建立HTTPS连接不仅需要Client与Server双方的TLS协议版本号兼容,还需要Cipher Suites(密码套件)兼容。关于什么是Cipher Suites可以自行查阅资料,本文不详细展开说明。Cipher Suites的样子如图所示: