当服务器响应 TLS 1.1 时,.net 4.7 无法创建 SSL 通道

.net 4.7 fails to create SSL channel when server responds with TLS 1.1

我正在尝试使用客户端证书身份验证执行 HTTPS GET 请求,但失败了

The request was aborted: Could not create SSL/TLS secure channel.

我正在使用 Java 尝试相同的请求并且它工作正常,我在 Java 日志中看到以下内容(仅删除有趣的部分):

*** ClientHello, TLSv1.2
main, WRITE: TLSv1.2 Handshake, length = 185

....

*** ServerHello, TLSv1.1
main, READ: TLSv1.1 Handshake, length = 3339

据我了解,这意味着该服务器出于某种原因不支持 TLS 1.2,但客户端正在接受并简单地回退到 TLS 1.1。

当我设置

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;

.NET 也可以正常工作。 现在的问题 - 为什么 .NET 不像 Java 那样回退到 TLS 1.1,我能否以某种方式启用回退(无需实际尝试 TLS 1.2,捕获异常并尝试使用 TLS 1.1)?

ServicePointManager.SecurityProtocol的描述中指出

Note that no default value is listed for this property, on purpose. The security landscape changes constantly, and default protocols and protection levels are changed over time in order to avoid known weaknesses. Defaults will vary depending on individual machine configuration, and on which software is installed, and on which patches have been applied.

Your code should never implicitly depend on using a particular protection level, or on the assumption that a given security level is used by default. If your app depends on the use of a particular security level, you must explicitly specify that level and then check to be sure that it is actually in use on the established connection. Further, your code should be designed to be robust in the face of changes to which protocols are supported, as such changes are often made with little advance notice in order to mitigate emerging threats.

虽然在 .NET 4.7 上,此 属性 的默认值应为 SystemDefault (source) and SystemDefault means "ask OS about list of default protocols" (and on Windows 10 TLS 1.1 and TLS 1.2 are enabled) - 此值仍会受到多个外部源(例如注册表项)的影响正如你在上面看到的,甚至通过安装的软件或应用的补丁)。正如我们在评论中弄清楚的那样,出于某种原因,您默认将其设置为 Ssl3 | Tls,这很糟糕,因为 Ssl3 甚至不安全,应该禁用。

因此,为了解决您的问题(以及将来的此类情况)- 始终列出您需要的协议,尤其是当您在多台客户端计算机上发布您的应用程序时,因为默认设置不可靠:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;