https://segmentfault.com/a/1190000021559557
此文主要内容翻译至博客How to Fix the SSL/TLS Handshake Failed Error?,并做了一些添加,修改和删除.
当浏览器向web服务器(如Apache)发送一个安全的请求时,ssl/tls握手过程就开始了.ssl/tls错误时有发生,其中最常见的错误就是SSL Handshake Failed error
.下面我们就来讲解什么是SSL/TLS握手失败,以及如何解决.
SSL/TLS握手过程简述
在讲述tls握手失败问题之前,有必要先简述一下tls握手过程:
- 当要建立一个tls加密的连接时.客户端首先发送一个client hello消息给服务端,其中包含了一个客户端生成的随机数 random_1, 客户端支持的加密套件(support ciphers), 以及支持的tls版本等信息;
- 服务端收到了客户端的请求时,会从client hello消息中取出随机数random_1, 客户端的加密套件等信息,确定使用哪一种加密套件,以及再生成一个随机数random_2, 并将这些信息包含在server hello消息中发送给客户端;然后服务端还会将自己的证书信息发送给客户端.
- 客户端收到服务服务端的消息和证书后,会从中取出服务端生成的随机数random_2,以及确定的加密套件等信息.并将服务端下发的证书拿到自己系统里的CA列表中进行验证,验证合法后从证书中取出服务端的公钥, 再生成一个随机数random_3.并用服务端的公钥对random_3进行加密生成一个key发给服务端.
- 服务端收到客户端发来的key之后,用自己的私钥对其解密,取出随机数random_3.
- 至此,客户端和服务端都拥有了random_1, random_2, random_3三个随机数,以及确定了相同的加密套件.现在只要根据相同的加密算法对这三个随机数进行加密生成一个密钥,服务端和客户端就拥有了这个相同的密钥.此后的连接中,服务端和客户端都使用这个密钥对信息进行加密,就可以通过这种对称加密的方式进行密文传输了.
- 我们可以发现,在服务端和客户端交换随机数的时候,是通过服务端向客户端下发公钥以非对称加密的形式完成的.当服务端和客户端都拿到了相同的三个随机数后,用这三个随机数生成了相同的密钥,此后的通信就是通过这个密钥加密和解密信息,实现了对称加密传输.
一些导致tls握手失败的原因
从以上tls握手过程来看,出现tls握手失败的原因有很多.只要客户端和服务端的握手过程中的某一个环节出了问题,都有可能导致tls握手失败.下面概括出现tls握手失败的一些常见问题.
原因 | 描述 | 哪里修复 |
---|---|---|
系统时间不准确 | 客户端的日期或时间不准确 | 客户端 |
浏览器错误 | 浏览器设置导致的错误 | 客户端 |
中间人 | 连接被第三方操控或劫持 | 客户端 |
协议不匹配 | 服务端不支持客户端所使用的协议 | 服务端 |
加密套件不匹配 | 服务端不支持客户端使用的加密套件 | 服务端 |
服务端启用了服务器名称指示(SNI-Enabled) | 由于启用了SNI导致服务端无法与客户端完成通信 | 服务端 |
证书错误 | <ul><li>证书中的域名与url中的域名不符</li><li>证书链不完整或错误</li><li>tls证书过期或被撤销</li></ul> | 服务端 |
下面,我们来详细的了解一下为何以上原因会导致tls握手失败,以及如何解决.
由客户端带来的问题以及解决方案
通常tls握手失败都是由服务端以及服务端tls配置问题导致的.
目前最主要的原因就是服务端的tls配置不支持ssl3.0.但是,客户端这边的问题也很有可能会导致的tls握手失败.比如,像系统时间不正确,或者浏览器更新所至等一些常见的客户端问题.
下面来详细解释一些常见的客户端问题.
1. 系统时间错误
这种情况通常不会发生,但有时系统时间会与真实时间不符.
原因是tls认证是有一个特定的有效期的,所以错误的系统时间可能会导致tls握手失败.
如果握手失败是由系统时间显示不正确导致,解决方法就是修正计算机的系统时间.
2. 浏览器错误
浏览器(客户端)的某些错误可能导致tls握手失败.例如浏览器某些设置错误,或由某些插件导致等原因,都有可能导致你访问合法网站时发生错误.但是定位和修复浏览器问题是非常困难的,最简单的方法是切换到其他浏览器来访问.
如果切换到其他浏览器还是tls握手失败,那么问题就不是由浏览器本身导致的.但还是有可能是由一些插件导致的,排查一下你的系统里装了哪些可以影响多个浏览器的插件,将它们关闭后,将浏览器恢复默认设置并重启.如果还有问题,那就可能是其他原因导致的.
3. 中间人
通常,中间人劫持是一种试图损害或窃取用户信息的犯罪活动.但也不完全是这种情况.处于检查或做负载均衡等原因,许多程序和设备也会先截取信息再将其发送到服务端,这也被称为中间人.
这些中间人设备有时也会导致tls握手失败.原因可能是网络防火墙阻止了连接,或是服务端网络的其他边缘设备的设置导致的.在这种情景下,导致错误的原因既可能来源于客户端,也可能来源于服务端.
如果问题来源于客户端,你可以通过调整自己系统VPN,防毒软件和防火墙的设置来打通连接.
如果问题是由服务端导致的,那大部分是由于网络中的边缘设备配置所造成的问题.
服务端导致的问题及解决方案
大部分情况下, tls握手失败都是由服务端问题所导致的. 其中有些问题很容易解决, 有些问题不容易解决,甚至有一些问题不值得去解决.
下面来看看一些常见的服务端问题.
1. 协议不匹配
这是一个在服务端和客户端都可能出现的错误, 需根据实际情况来判断是否要去解决这个问题. 而且当问题是出现在加密或协议相关时,建议的解决方法是更新到新的版本, 而不是回退到旧版本.
例如:
虽然tls1.2已经诞生十多年了,但仍有一小部分网站还不支持. 而且早在2018年3月, tls1.3的最终版本就在RFC 8446 by the IETF上发版了,并建议所有网站添加对tls1.3版本的支持.
所以, 如果tls握手失败的原因是协议不匹配,那通常原因是服务端和客户端支持的tls版本不同.
例如:
- 客户端支持tls1.0和tls1.1版本,但服务端只支持tls1.2
上面这个例子就是tls协议不匹配.但是,在这种情况下,要修复这个问题,不应该是服务端来匹配低版本的协议,而应该是客户端升级到tls1.2来匹配服务端较新的协议. 在目前,我们的建议是必须支持tls1.2和tls1.3协议,对于还不支持的网站必须添加上这两个版本.
2. 加密套件不匹配
tls/ssl并不是通过一个通过自身可以解决所有问题的算法,而是一系列不同算法的结合,不同的算法用以实现不同的功能,它们结合在一起组成了tls/ssl.
tls1.3版本的加密套件得到了进一步的完善.在这之前, 加密套件的算法主要包含以下功能:
- 对称密钥会话加密(Symmetric Session Key Encryption)
- 非对称公钥加密(Asymmetric Public Key Encryption)
- 证书签名哈希(Signature Hashing)
- 密钥生成(Key Generation)
不同组织和机构有不同的加密标准, 支持不同的加密套件.所以为了匹配服务端, 客户端必须提供多种加密套件的支持. 同样,一般服务端也会支持多种加密套件.
在网络连接中经常会发生这种情况, 你尝试和服务端建立一个tls连接, 在客户端和服务端之间存在一个边缘设备(如负载均衡, 反向代理等), 这个边缘设备接收并解密了你的https流量,再重新加密发送到在他之后的服务端. 但如果这个边缘设备和服务端之间的加密套件不匹配, 就会导致错误. 同协议版本不匹配类似, 加密套件不匹配时, 通常是采取升级而不是降级来解决问题.
最后强调一点, 被弃用的协议版本或密码套件通常是因为他们存在安全隐患. 所以,如果你采取降级来解决此类问题将会降低https连接的安全性.
3. tls/ssl证书错误
许多原因都会导致浏览器判定tls证书不合法, 这时浏览器就会阻止tls握手连接. 在接下来的小节中, 我们会深入探讨由于此类技术问题所引发的tls握手失败问题.
- 域名不匹配: 网站域名与证书中的不相匹配.
- 证书链不正确: 证书链中缺少中间证书.
- 证书过期或被撤销: 服务端使用了不受信任, 过期, 或被撤销的tls证书.
- 使用自签名证书: 使用自签名证书或内部网络路径混乱
4. 域名错误
在以前,一个网站的非www域名和www域名之间存在着问题,但是后来证书颁发机构允许一个证书可以签发多个子域名(SAN),已经几乎解决了这个问题.处理证书域名错误的最好方法就是从新签发一个新证书,或者使用通配符证书.
5.证书链不正确
SSL/TLS和PKI信任模型通常依赖于根程序(Root program),这是存储在计算机系统上的受信任CA根证书的集合。其中一些根程序例如:
- 火狐浏览器使用的Mozilla根程序.
- 安卓系统使用的Google根程序.
- IOS和macOS系统所使用的Apple根程序.
- Windows系统使用的Microsoft根程序.
CA根程序十分重要,虽然它不直接签发证书,但证书机构会利用中间根证书来签发终端用户所使用的tls叶证书. 这就是证书链的运作方式, CA根证书被用来签发中间根, 中间根又用来签发其他中间根, 最终直到终端用户的tls叶证书.
无论什么时候,只要浏览器收到了张tls证书,都会去去检查它签名的真实性. 在签发该证书的中间根中验证它的数字签名,然后再将该中间根的数字签名拿到签发它的中间根上去验证,如此层层递进,最终会追溯到一个受信任的CA根证书.
因此,无论处于什么原因导致这个检验过程不能完整的进行,甚至浏览器只是不能定位其中一个中间根,都会导致tls握手失败的错误.
解决方案是安装缺失了的中间证书.缺失的中间证书可以在你购买tls证书的CA机构网站找到.
6. 证书过期或被注销
当前,tls证书的最大有效期是2年. 因此,如果你的证书过期或者因为某些原因被注销了,将会导致tls握手失败的错误.解决方法是重新购买和安装一份合法的证书.
7. 使用自签名证书
如果你的暴露在公网上的网站使用的是自签名证书,这是不被信任的,将会导致错误. 要解决这个错误,你需要去一个受信任的CA机构重新签署一份tls证书.
8. 开启了服务器名称标识(SNI-Enabled)
通常,这是一个发生在服务端设备之间的内部问题,但有时一个未开启SNI的客户端去访问一个开启了SNI的服务端,就可能发生tls握手错误.
要解决这个问题,你必须确定服务器的主机名和端口号,同时还要验证服务器是否开启了SNI验证,以及验证服务器是否传递了所有的必要信息.
总结
通常网站管理者不需要做任何改变, 但如果一旦遇到了此类问题,绝对不能忽视. 尽管有时问题是由客户端导致的, 但正如此文中提到的一样,其中大多数情况都是有服务端导致的.
所以,如果你只是一个普通的用户,你能做的事情是有限的. 最好的方法就是将问题上报给网站管理员,等待他们来修复.