随机请求已中止:无法创建 SSL/TLS 安全通道。返回代码=MessageAltered

Random The request was aborted: Could not create SSL/TLS secure channel. Returned code=MessageAltered

大约一千个 HTTPS 请求中有一个会抛出以下异常:

System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
    at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request)
    at System.Net.WebClient.DownloadString(Uri address)

来自 System.Net 的日志如下所示:

2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] Associating HttpWebRequest#37618637 with ServicePoint#28841767
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] Associating Connection#16407032 with HttpWebRequest#37618637
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net.Sockets | [2688] Socket#42531032 - Created connection from x.x.x.x:12345 to y.y.y.y:443.
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] Connection#16407032 - Created connection from x.x.x.x:12345 to y.y.y.y:443.
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] TlsStream#54603865::.ctor(host=www.remoteservice.com, #certs=0)
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] Associating HttpWebRequest#37618637 with ConnectStream#27023101
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] HttpWebRequest#37618637 - Request: GET /api/v3/method HTTP/1.1
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] ConnectStream#27023101 - Sending headers
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] SecureChannel#66031633::.ctor(hostname=www.remoteservice.com, #clientCertificates=0, encryptionPolicy=RequireEncryption)
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] SecureChannel#66031633 - Left with 0 client certificates to choose from.
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] Using the cached credential handle.
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = (null), targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:10:17.1031 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=379, returned code=ContinueNeeded).
2016-09-20 15:10:17.1656 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505f981f0, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:10:17.1656 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
2016-09-20 15:10:17.1656 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505f981f0, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:10:17.1656 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
2016-09-20 15:10:17.1656 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505f981f0, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:10:17.1656 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
2016-09-20 15:10:17.1656 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505f981f0, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:10:17.4937 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=574, returned code=ContinueNeeded).
2016-09-20 15:10:17.5562 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505f981f0, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:10:17.5562 | INFO | 72 | System.Net | [2688] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=MessageAltered).
2016-09-20 15:10:17.5562 | ERROR | 72 | System.Net | [2688] Exception in HttpWebRequest#37618637:: - The request was aborted: Could not create SSL/TLS secure channel..
2016-09-20 15:10:17.5562 | ERROR | 72 | System.Net | [2688] Exception in HttpWebRequest#37618637::GetResponse - The request was aborted: Could not create SSL/TLS secure channel..
2016-09-20 15:10:17.5562 | ERROR | 72 | System.Net | [2688] Exception in HttpWebRequest#37618637:: - The request was aborted: The request was canceled..

InitializeSecurityContext 以行结尾:

InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=MessageAltered)

为了比较,这里是成功的 HTTPS 调用之一:

2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] Associating HttpWebRequest#23767080 with ServicePoint#28841767
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] Associating Connection#23643787 with HttpWebRequest#23767080
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net.Sockets | [1900] Socket#66957105 - Created connection from x.x.x.x:12345 to y.y.y.y:443.
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] Connection#23643787 - Created connection from x.x.x.x:12345 to y.y.y.y:443.
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] TlsStream#51402822::.ctor(host=www.remoteservice.com, #certs=0)
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] Associating HttpWebRequest#23767080 with ConnectStream#55741749
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] HttpWebRequest#23767080 - Request: GET /api/v3/method/123 HTTP/1.1
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] ConnectStream#55741749 - Sending headers
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] SecureChannel#20739431::.ctor(hostname=www.remoteservice.com, #clientCertificates=0, encryptionPolicy=RequireEncryption)
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] SecureChannel#20739431 - Left with 0 client certificates to choose from.
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] Using the cached credential handle.
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = (null), targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:11:21.9128 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=379, returned code=ContinueNeeded).
2016-09-20 15:11:21.9909 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505fb0480, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:11:21.9909 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
2016-09-20 15:11:21.9909 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505fb0480, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:11:21.9909 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
2016-09-20 15:11:21.9909 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505fb0480, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:11:21.9909 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
2016-09-20 15:11:21.9909 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505fb0480, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:11:22.3190 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=574, returned code=ContinueNeeded).
2016-09-20 15:11:22.3815 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505fb0480, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:11:22.7878 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
2016-09-20 15:11:22.7878 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505fb0480, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:11:22.7878 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
2016-09-20 15:11:22.7878 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = e239863c90:3505fb0480, targetName = www.remoteservice.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
2016-09-20 15:11:22.7878 | INFO | 47 | System.Net | [1900] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=OK).
2016-09-20 15:11:22.7878 | INFO | 47 | System.Net | [1900] Remote certificate: [Version] V3 (more info on certificate here)
2016-09-20 15:11:22.7878 | INFO | 47 | System.Net | [1900] SecureChannel#20739431 - Remote certificate was verified as valid by the user.
2016-09-20 15:11:22.7878 | INFO | 47 | System.Net | [1900] ProcessAuthentication(Protocol=Tls12, Cipher=Aes256 256 bit strength, Hash=32781 0 bit strength, Key Exchange=DiffieHellman 4096 bit strength).
2016-09-20 15:11:22.8971 | INFO | 47 | System.Net | [1900] Connection#23643787 - Received status line: Version=1.1, StatusCode=200, StatusDescription=OK.
2016-09-20 15:11:22.8971 | INFO | 47 | System.Net | [1900] Connection#23643787 - Received headers
2016-09-20 15:11:22.8971 | INFO | 47 | System.Net | [1900] ConnectStream#43287324::ConnectStream(Buffered -1 bytes.)
2016-09-20 15:11:22.8971 | INFO | 47 | System.Net | [1900] Associating HttpWebRequest#23767080 with ConnectStream#43287324
2016-09-20 15:11:22.8971 | INFO | 47 | System.Net | [1900] Associating HttpWebRequest#23767080 with HttpWebResponse#32954516
2016-09-20 15:11:22.8971 | INFO | 47 | System.Net | [1900] ContentLength=-1

ServicePointManager配置如下:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
ServicePointManager.Expect100Continue = false;
ServicePointManager.DefaultConnectionLimit = 24;

.NET Framework 版本为 4.5。

你知道为什么会发生这种情况吗?

从 Schannel 的角度来看,MessageAltered 意味着:TLS1_ALERT_BAD_RECORD_MAC 根据 RFC 5246:https://www.rfc-editor.org/rfc/rfc5246 意味着:

bad_record_mac 如果收到不正确的记录,则会返回此警报 MAC。如果发送警报,则也必须返回此警报,因为 以无效方式解密的 TLSCiphertext:要么它不是 甚至是块长度的倍数,或其填充值,当 查了,不对。此消息始终是致命的,应该 在正确实现之间的通信中永远不会被观察到 (除非消息在网络中损坏)。

收到的消息似乎在某些地方已损坏 way/form 导致错误 - 因为无法执行解密。您可能必须联系服务器供应商以纠正他们的问题,或者如果您无法影响服务器人员,请重试请求 - 前提是后续请求成功。