015: TLS1.2 握手的过程是怎样的?

之前谈到了 HTTP 是明文传输的协议,传输保文对外完全透明,非常不安全,那如何进一步保证安全性呢?

由此产生了 HTTPS,其实它并不是一个新的协议,而是在 HTTP 下面增加了一层 SSL/TLS 协议,简单的讲,HTTPS = HTTP + SSL/TLS

那什么是 SSL/TLS 呢?

SSL 即安全套接层(Secure Sockets Layer),在 OSI 七层模型中处于会话层(第 5 层)。之前 SSL 出过三个大版本,当它发展到第三个大版本的时候才被标准化,成为 TLS(传输层安全,Transport Layer Security),并被当做 TLS1.0 的版本,准确地说,TLS1.0 = SSL3.1

现在主流的版本是 TLS/1.2, 之前的 TLS1.0、TLS1.1 都被认为是不安全的,在不久的将来会被完全淘汰。因此我们接下来主要讨论的是 TLS1.2, 当然在 2018 年推出了更加优秀的 TLS1.3,大大优化了 TLS 握手过程,这个我们放在下一节再去说。

TLS 握手的过程比较复杂,写文章之前我查阅了大量的资料,发现对 TLS 初学者非常不友好,也有很多知识点说的含糊不清,可以说这个整理的过程是相当痛苦了。希望我下面的拆解能够帮你理解得更顺畅些吧 : )

传统 RSA 握手

先来说说传统的 TLS 握手,也是大家在网上经常看到的。我之前也写过这样的文章,(传统RSA版本)HTTPS为什么让数据传输更安全,其中也介绍到了对称加密非对称加密的概念,建议大家去读一读,不再赘述。之所以称它为 RSA 版本,是因为它在加解密pre_random的时候采用的是 RSA 算法。

TLS 1.2 握手过程

现在我们来讲讲主流的 TLS 1.2 版本所采用的方式。

刚开始你可能会比较懵,先别着急,过一遍下面的流程再来看会豁然开朗。

step 1: Client Hello

首先,浏览器发送 client_random、TLS版本、加密套件列表。

client_random 是什么?用来最终 secret 的一个参数。

加密套件列表是什么?我举个例子,加密套件列表一般张这样:

TLS_ECDHE_WITH_AES_128_GCM_SHA256

意思是TLS握手过程中,使用ECDHE算法生成pre_random(这个数后面会介绍),128位的AES算法进行对称加密,在对称加密的过程中使用主流的GCM分组模式,因为对称加密中很重要的一个问题就是如何分组。最后一个是哈希摘要算法,采用SHA256算法。

其中值得解释一下的是这个哈希摘要算法,试想一个这样的场景,服务端现在给客户端发消息来了,客户端并不知道此时的消息到底是服务端发的,还是中间人伪造的消息呢?现在引入这个哈希摘要算法,将服务端的证书信息通过这个算法生成一个摘要(可以理解为比较短的字符串),用来标识这个服务端的身份,用私钥加密后把加密后的标识自己的公钥传给客户端。客户端拿到这个公钥来解密,生成另外一份摘要。两个摘要进行对比,如果相同则能确认服务端的身份。这也就是所谓数字签名的原理。其中除了哈希算法,最重要的过程是私钥加密,公钥解密

step 2: Server Hello

可以看到服务器一口气给客户端回复了非常多的内容。

server_random也是最后生成secret的一个参数, 同时确认 TLS 版本、需要使用的加密套件和自己的证书,这都不难理解。那剩下的server_params是干嘛的呢?

我们先埋个伏笔,现在你只需要知道,server_random到达了客户端。

step 3: Client 验证证书,生成secret

客户端验证服务端传来的证书签名是否通过,如果验证通过,则传递client_params这个参数给服务器。

接着客户端通过ECDHE算法计算出pre_random,其中传入两个参数:server_paramsclient_params。现在你应该清楚这个两个参数的作用了吧,由于ECDHE基于椭圆曲线离散对数,这两个参数也称作椭圆曲线的公钥

客户端现在拥有了client_randomserver_randompre_random,接下来将这三个数通过一个伪随机数函数来计算出最终的secret

step4: Server 生成 secret

刚刚客户端不是传了client_params过来了吗?

现在服务端开始用ECDHE算法生成pre_random,接着用和客户端同样的伪随机数函数生成最后的secret

注意事项

TLS的过程基本上讲完了,但还有两点需要注意。

第一、实际上 TLS 握手是一个双向认证的过程,从 step1 中可以看到,客户端有能力验证服务器的身份,那服务器能不能验证客户端的身份呢?

当然是可以的。具体来说,在 step3中,客户端传送client_params,实际上给服务器传一个验证消息,让服务器将相同的验证流程(哈希摘要 + 私钥加密 + 公钥解密)走一遍,确认客户端的身份。

第二、当客户端生成secret后,会给服务端发送一个收尾的消息,告诉服务器之后的都用对称加密,对称加密的算法就用第一次约定的。服务器生成完secret也会向客户端发送一个收尾的消息,告诉客户端以后就直接用对称加密来通信。

这个收尾的消息包括两部分,一部分是Change Cipher Spec,意味着后面加密传输了,另一个是Finished消息,这个消息是对之前所有发送的数据做的摘要,对摘要进行加密,让对方验证一下。

当双方都验证通过之后,握手才正式结束。后面的 HTTP 正式开始传输加密报文。

RSA 和 ECDHE 握手过程的区别

  1. ECDHE 握手,也就是主流的 TLS1.2 握手中,使用ECDHE实现pre_random的加密解密,没有用到 RSA。

  2. 使用 ECDHE 还有一个特点,就是客户端发送完收尾消息后可以提前抢跑,直接发送 HTTP 报文,节省了一个 RTT,不必等到收尾消息到达服务器,然后等服务器返回收尾消息给自己,直接开始发请求。这也叫TLS False Start

微信公众号: 前端三元同学

获取更多资料/联系加交流群