Https之(一)TLS介绍及握手过程详解
文章目录
- 简介
- TLS
- TLS第一次握手
- 1.Client Hello
- TLS第二次握手
- 2.Server Hello
- 3.Certificate
- 4.Server Hello Done
- TLS第三次握手
- 5.Client Key Exchange
- 6.Change Cipher Spec
- 7.Encrypted Handshake Message
- TLS第四次握手
- 8.New Session Ticket
- 9.Change Cipher Spec
- 10.Encrypted Handshake Message
- 总结
简介
我们知道http传输数据是明文传输,明文传输存在三个问题:
- 窃听风险:由于是明文传输,到达目标之前的所有链路都可以看到传输的内容。
- 篡改风险:如果传输过程中间数据被修改,接收方也无法得知。
- 冒充风险:由于知道传输的内容,中间人可以冒充接收方。
在计算机发展的早期只是使用http传输简单的数据,发展到现在绝大部分数据传输都是基于http协议,如果还使用明文传输显然不太安全,特别是涉及账号密码相关的内容,https就是在http的基础上添加了安全传输层,其中s代表SSL(Secure Sockets Layer)或者TLS(Transport Layer Security),SSL是早期的版本,由网景公司在1990年代早期开发。TLS是其后续版本,由互联网工程任务组(IETF)开发,SSL有SSL1.0、SSL2.0和SSL3.0,TLS有TLS1.0、TLS1.1、TLS1.2和TLS1.3,目前主流的版本是TLS1.2和TLS1.3。下面我们来介绍TLS是怎么实现安全传输的。我们以目前主流的TLS1.2作为介绍对象。
TLS
我们先看下TLS的流程:
根据上图我们可以把TLS分为以下几步:
1.服务端生成一对非对称加密的密钥对,把自己的公钥交给CA机构生成一个证书,什么是CA呢?因为非对称加密通过公钥加密数据,通过私钥解密数据,服务端拥有公钥私钥,但是客户端什么都不知道,所以需要将公钥传给客户端,但是直接发给客户端可能会被中间人拦截替换,TLS通过引入一个双方可以信任的第三方即CA来解决这个问题。
- CA会将服务端的公钥、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值(也称证书指纹)
- 然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature(证书签名)
- 最后将 Certificate Signature 添加在文件证书上,形成数字证书。由于证书签名使用CA的私钥加密,解密自然只能用CA的公钥。我们的客户端(Android,Windows,iOS等)都会集成全球主流的CA的公钥信息到操作系统中。
2.当客户端向服务端请求数据的时候,服务端把这个证书发送给客户端,客户端拿到证书后可以得到服务端的公钥、颁发者、有效时间、证书签名和所属的CA等信息。
- 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1
- 再从操作系统中寻找这个CA的公钥,通过公钥解密证书里的签名数据得到Hash值H2
- 最后比较 H1 和 H2,如果值相同,则为可信赖的证书。
通过CA客户端可以验证服务端的身份,防止有人冒充。
3.客户端已经拿到了可以用来加密的公钥,正常来说现在已经可以进行加密通讯了,但是由于非对称加密较复杂,加密耗时较久,而且加密后内容明显变大,所以在频繁的通讯中使用是非常不划算的,所以这里并没有直接用公钥加密传输数据,而是引入了对称加密,在客户端随机生成一个对称加密密钥,并使用公钥加密后传给服务器,由于只有服务器有私钥,所以中间拦截也没用,服务器接收到数据后解密拿到对称加密密钥,后续的通讯就使用对称加密进行加密。(虽然对称加密的安全性不如非对称加密,但是由于每次连接都会生成一个随机的密钥,所以安全性上也是可以接受的。)
上面只是大致的流程,实际实现和上面说的还是有很大区别的,下面我们分析一次实际中TLS握手的完整过程,什么是TLS的握手呢?其实就是通讯双方通过上面的方法协商一个共同的密钥的过程,他的完整流程是这样的:
上图有多次通信过程,可以分成4次握手,下面我们通过抓包看一下实际的TLS的握手过程,首先看一下wireshark中完整的TLS握手记录:
上图中有多个握手过程,我把其中一个握手的完整过程标记出来了,下面我们来详细介绍每一步的作用。
TLS第一次握手
1.Client Hello
上图是client hello的所有内容,我们重点关注红框中的内容:
1.Version是客户端的TLS版本,我们看到是1.2
2.Random是客户端生成的一个随机数,用于生成加密密钥,前面我们说过客户端拿到服务端公钥后会生成一个随机数当作后续通讯加密的密钥,并把这个密钥用公钥加密后发送给服务端,其实这个密钥不止一个随机数,而是三个随机数拼成的,其一就是这里的随机数,其二是服务端server hello时也会传过来的一个服务端生成的随机数,最后才是之前说的随机数,通过三个随机数生成最终的密钥是为了保证随机性和安全性。
3.Cipher Suites是客户端支持的加密套件,我们上面说的对称加密和非对称加密并没有固定的加密算法,这个有很多选择,我们看下客户端支持的加密套件有哪些:
这个密码套件看起来真让人头晕,好一大串,但是其实它是有固定格式和规范的。基本的形式是「密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法」, 一般 WITH 单词前面有两个单词,第一个单词是约定密钥交换的算法,第二个单词是约定证书的验证算法。比如我们目前分析的这个TLS_RSA_WITH_AES_128_GCM_SHA256密码套件的意思就是:
- 由于 WITH 单词只有一个 RSA,则说明握手时密钥交换算法和签名算法都是使用 RSA;
- 握手后的通信使用 AES 对称算法,密钥长度 128 位,分组模式是 GCM;
- 摘要算法 SHA256 用于消息认证和产生随机数;
4.support_versions是客户端支持的所有TLS版本,前面的version是客户端想要使用的版本,但是服务端不一定支持,所以需要把支持所有版本给到服务端,如果服务端不支持version的版本,就在support_versions选一个。
5.session_ticket是用于复用之前的TLS连接用的,这个后面会介绍。
TLS第二次握手
2.Server Hello
1.Version是服务端选择的TLS版本
2.Random是服务端生成的一个随机数,用于生成加密密钥
3.Cipher Suites是服务端选择的加密套件
3.Certificate
这一步是将服务器的证书发送给客户端,客户端拿到证书后会去进行验证,并拿到公钥。
上图中服务器给了两个证书,这是为什么呢?这就要说到CA的证书链机制了,服务端的证书并不一定是CA根证书签发的,而可能是CA的二级证书签发的,CA下面会有二级三级乃至多级代理,如果是二级代理签发的证书,就要先用根证书验证二级代理的证书,二级代理的证书没问题,再用二级代理的证书验证服务器的证书。
所以上图的第一个证书是服务器证书,第二个证书是二级代理的证书,先找到二级代理所属的CA,去验证二级证书,验证无误后再用二级证书去验证服务器证书。
4.Server Hello Done
服务端已经完成hello,为什么需要这一步呢?
在Server Hello
之后,服务器通常会发送一系列消息,包括:
Certificate
(包含服务器的证书链)Server Key Exchange
(如果证书不包含足够的信息进行密钥交换,例如使用DHE/ECDHE算法时)Certificate Request
(可选,如果服务器要求客户端认证)...
(其他可能的扩展消息)
这些消息的数量和类型是可变的,取决于协商的加密套件、服务器配置和是否要求客户端认证。
Server Hello Done
的唯一作用就是清晰、明确地告诉客户端:“我已经发送完所有我这边在握手这一阶段需要发送的信息了,没有更多这类消息了。”
TLS第三次握手
5.Client Key Exchange
将用公钥加密的pre-master传递给服务端,服务端拿到直接用私钥解密就可以拿到pre-master,加上client的random和server的radom就可以得到回话密钥。
客户端随机数 + 服务端随机数 + 预主密钥 = 主密钥 ==> 会话密钥
6.Change Cipher Spec
告诉服务端开始用会话密钥进行加密通讯了
7.Encrypted Handshake Message
把客户端之前所有发送的数据做个摘要,再用会话密钥(master secret)加密一下,让服务器做个验证,验证加密通信是否可用和之前握手信息是否有被中途篡改过。
TLS第四次握手
8.New Session Ticket
将session_ticket发送给客户端保存,session_ticket是用于复用之前的TLS连接用的,由于TLS的握手比较繁琐,自然就比较耗时,所以当握手完成后服务器端将本次的会话数据进行加密(会话标识符、证书、密码套件和主密钥等),加密后生成一个ticket票据(只有服务器可以解密),并将票据通过NewSessionTicket子消息发送给客户端,客户端保存这个ticket。当连接断开后重新连接的时候就可以在client hello中将这个ticket发送给服务端,服务器端解密校验无误后拿到主密钥,将主密钥和client hello中的random以及服务端生成的即将在server hello中传输的random三个数据生成一个新的密钥,然后server hello的时候客户端也用同样的三个数据生成这个密钥,这样就协商了一个相同的密钥,后续就用这个密钥进行加密通讯,如此恢复上一次会话就可以省掉之后的很多步骤。
9.Change Cipher Spec
和客户端发送的Change Cipher Spec操作相同,告诉客户端我准备好使用会话密钥了
10.Encrypted Handshake Message
把服务端之前所有发送的数据做个摘要,再用会话密钥(master secret)加密一下,让客户端做个验证,验证加密通信是否可用和之前握手信息是否有被中途篡改过。
总结
到这里TLS的流程就介绍完了,我们再看看开头说的http的三个问题是怎么解决的:
- 窃听风险:通过会话密钥加密数据。
- 篡改风险:通过CA对证书进行签名,对TLS握手过程进行摘要计算。
- 冒充风险:向CA验证证书。
虽然解决了这三个问题,但是现在的TLS还是有缺陷的,那就是不支持前向保密,因为客户端传递pre-master(用于生成对称加密密钥的条件之一)给服务端时使用的是公钥加密的,服务端收到后,会用私钥解密得到随机数。所以一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。
为了解决这一问题,于是就有了 DH 密钥协商算法TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,和我们上面介绍的TLS_RSA_WITH_AES_128_GCM_SHA256区别就是使用了ECDHE的密钥协商算法,后面我们介绍一下这个算法。
下一篇:Https之(二)TLS的DH密钥协商算法