https tls/ssl握手流程解析
之前转载过一篇关于https的流程及证书的一系列图片的文章https://blog.csdn.net/taoqilin/article/details/85471589 ,直观却也抽象,这篇文章对流程的描述非常到位,共欣赏。
注意: 下面解释过程中用到的具体协议版本、算法和值都是示例,实际中可能不是这些
ClientHello
client->server:
hello,咱建立个连接呗,我这边的支持的最高版本是TLS1.1,
支持的密码套件(cipher suite)有“TLS_RSA_WITH_AES_128_CBC_SHA”和“TLS_RSA_WITH_AES_256_CBC_SHA256”,
支持的压缩算法有DEFLATE,我这边生成的随机串是abc123456。
这里有几点需要解释一下:
- 客户端会把自己最喜欢的密码套件放在最前面,这样服务器端就会根据客户端的要求优先选择排在前面的算法套件
- 密码套件就是一个密码算法三件套,里面包含了一个非对称加密算法,一个对称加密算法,以及一个数据摘要算法。以TLS_RSA_WITH_AES_128_CBC_SHA为例,RSA是非对称加密算法,表示后面用到的证书里面的公钥用的是RSA算法,通信的过程中需要签名的地方也用这个算法,并且密码(key)的交换过程也使用这个算法;AES_128_CBC是对称加密算法,用来加密握手后传输的数据,其密码由RSA负责协商生成;SHA是数据摘要算法,表示后面交换的证书里签名
用到的摘要算法是sha1,并且后续通信过程中需要用到数据校验的地方也是用的这个算法。在Record
Protocol协议中,摘要算法是必须的,即数据包都需要有校验码,而签名是可选的。 - ClientHello里面还可以包含session id,即表示重用前面session里的一些内容,比如已经协商好的算法套件等,服务器收到session id后会去内存里面找,如果这是一个合法的session id,那么它就可以选择重用前面的session,这样可以省去很多握手的过程。为了简化讨论,这里不介绍session重用的问题。
ServerHello
server收到client的hello消息后,就在自己加载的证书中去找一个和客户支持的算法套件相匹配的证书,并且挑选一个自己也支持的对称加密算法(证书里面只有非对称加密和摘要算法,不包含对称加密算法)。如果出现下面几种情况,握手失败:
- 客户端支持的TLS版本太低,比如server要求最低版本为1.2,而客户端支持的最高版本是1.1
- 根据客户端所支持的密码套件,找不到相应要求的证书
- 无法就支持的对称加密算法达成一致
如果一切都OK,那么服务器端将返回ServerHello:
server->client:
hello,没问题,我们就使用TLS1.1吧,
算法采用“TLS_RSA_WITH_AES_256_CBC_SHA256”,这个加密强度更高更安全,
压缩就算了,我这边不支持,我这边生成的随机数是654321def。
如果server支持session重用的话,这里还会返回session id
Certificate
服务器在发送完ServerHello之后紧接着发送Certificate消息,里面包含自己的证书。
当然这步在有些情况下可以忽略掉,就是非对称加密算法选择使用dh_anon,当然这是特殊的情况,并且也不安全,所以这里就不展开讨论。
server->client: 这是我的证书(身份证),请过目
ServerKeyExchange(可选)
在前面的ServerHello中,双方已经协商好了密码套件,对于套件里面的非对称加密算法,有些需要更多的信息才能生成一个可靠的密码,而有些不需要,比如RSA,就不需要发送这个消息,客户端自己生成一个准密码(premaster)就可以了,而有些算法,比如DHE_RSA,就需要发送一点特殊的信息给客户端,便于它生成premaster。
premaster可以理解为最终密码的初级版本,有了这个密码之后,稍微再做一下计算就可以得到最终要使用的对称加密的密码
server->client: 这是生成premaster所需要的一些信息,请查收
CertificateRequest(可选)
只有在需要验证客户端的身份的时候才用得着,在大部分情况下,尤其是HTTPS,这一步不需要。比如我们访问银行的网站,我们只要保证那确实是银行的网站就可以了,银行验证我们是通过账号密码,而不是我们的证书。而U盾就是一个验证客户端的例子,银行给你的U盾里面有你的证书,你通过U盾访问银行的时候,银行会验证U盾里面证书是不是你的,这种情况下,你和银行之间进行TLS握手的时候,银行会给你发这个CertificateRequest请求。
你的数字证书有一对,一份在U盾里的私钥,一份在银行的公钥(其实两份银行都有)。U盾的原理很 类似于双向认证的TLS(SSL) ,或者其它用到RSA的双向证书验证手段,以下步骤可能和U盾实际执行的有所区别,但本质相同:
银行先给你一个"冲击",它包含了随机数,以及该随机数HASH,它们都由公钥加密,这样就可以保证只有你能解密这个"冲击"
你计算该随机数的HASH,并和用私钥解出的HASH,两者相同后,便可确认银行的身份
接下来,以一个只有你和银行知道的算法,利这个随机数和一些其它信息,生成"响应"和相应的HASH,再用私钥加密后发回银行。(此时银行也以相同的算法计算该"响应")
银行用公钥解密,并验证HASH正确,接下来银行比较两个"响应"是否相同,相同的话客户的身份也确认了
至于私钥的保密性由U盾来完成。U盾的控制芯片被设计为只能写入证书,不能读取证书,并且所有利用证书进行的运算都在U盾中进行。所以,只能从U盾读出运算结果。
server->client: 把你的证书(身份证)也给我看看,我要确认一下你是不是XXX。
ServerHelloDone
server->client: 我要告诉你的就是这么多了,处理完了给我个回话吧。
Certificate(可选)
如果客户端在前面收到了服务器的CertificateRequest请求,那么将会在这里给服务器发送自己的证书,就算自己没有证书,也要发送这个消息告诉服务器端自己没有证书,然后由服务器端来决定是否继续。
client->server: 这是我的证书(身份证),请过目
ClientKeyExchange
客户端验证完服务器端的证书后(怎么验证证书将在后面介绍),就会生成一个premaster,生成的方式跟采用的密码交换算法有关,以TLS_RSA_WITH_AES_128_CBC_SHA为例,其密码交换算法是RSA,于是客户端自己直接生成一个48字节长度的premaster即可,不需要服务器发过来的ServerKeyExchange。
client->server:
这是计算真正密码要用到的premaster,它是用你证书里的公钥加密了的哦,
记得用你的私钥解密后才能看到哦
CertificateVerify(可选)
如果客户端给服务器发了证书,就需要发送该消息给服务器,主要用于验证证书对应的私钥确实是在客户端手里。
client->server:
这是一段用我私钥加密的数据,你用我给你的证书里的公钥解密看看,
如果能解开,说明我没骗你,私钥确实是在我手里,
并不是我随便找了一个别人的证书忽悠你
发送的消息里面都带有校验码,所以解密后计算下校验码,能对上说明解密成功
Finished
当前面的过程都没问题后,服务器和客户端都根据得到的信息计算对称加密用的密码,这是RFC里面给出的计算方法:
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)
[0..47];
虽然不太了解PRF的细节,但至少客户端和服务器端用的算法和输入都是一样的,所以得到的master密码也是一样的。这里pre_master_secret就是ClientKeyExchange里面客户端发给服务器端的premaster,ClientHello.random和ServerHello.random分别是握手开始时双方发送的hello请求中的随机字符串。
这里加入随机数的原因主要是为了防止重放攻击,保证每次握手后得到的密码都是不一样的
然后双方将自己缓存的握手过程中的数据计算一个校验码,并用对称加密算法和刚算出来的master密码加密,发给对方,这一步有两目的,一个是保证双方算出来的master密码都是一样的,即我这边加密的数据你那边能解开;另一个目的是确保我们两个人的通信过程中的每一步都没有被其他人篡改,因为握手的前半部分都是明文,所以有可能被篡改,只要双方根据各自缓存的握手过程的数据算出来的校验码是一样的,说明中间没人篡改过。
client->server: 这是用我们协商的对称加密算法和密码加密过的握手数据的指纹,看能不能解开,并且和你那边算出来的指纹是一样的
server->client: 这是用我们协商的对称加密算法和密码加密过的握手数据的指纹,你也看看能不能解开,并且和你那边算出来的指纹是一样的
如果双方发送完Finished而对方没有报错,握手就完成了,双发都得到了密码,并且这个密码别人不知道,后续的所有数据传输过程都会用这个密码进行加密,加密算法就是ServerHello里面协商好的对称加密算法。
在上面握手的过程中,一旦有任何一方觉得有问题,都可能随时终止握手过程
握手不成功常见问题
配置好了之后还是连不上,一般会是下面几种问题:
- 版本不一致,有一方的版本太低,另一方为了安全不同意跟它通信
- 无法就cipher suite达成一致,有一方支持的加密算法太弱,安全程度不够
- 证书有问题,没法通过验证
- 服务器端需要验证客户端的证书,而客户端没有配置
上一篇: javascript 倒计时代码
推荐阅读
-
TCP/IP协议三次握手与四次握手流程解析
-
在 Tomcat 中配置 SSL/TLS 以支持 HTTPS
-
加密算法与CA证书(CA,SSL/TLS,HTTPS,openssl)
-
【转载】网站配置Https证书系列(一):腾讯云申请免费的SSL证书的流程步骤(即https安全连接使用的证书)
-
Https请求被中止: 未能创建 SSL/TLS 安全通道
-
https tls/ssl握手流程解析
-
加密基础知识三 TLS/SSL HTTPS
-
TCP/IP协议三次握手与四次握手流程解析
-
【转载】网站配置Https证书系列(一):腾讯云申请免费的SSL证书的流程步骤(即https安全连接使用的证书)
-
Https请求被中止: 未能创建 SSL/TLS 安全通道