在上一节,我们看到了浏览器地址栏的小锁,知道它代表一个加密通道已经建立。但你有没有想过:那个加密通道到底是怎么建成的?在你按下回车后、网页出现前的短短几百毫秒里,客户端和服务器之间到底说了什么?
这背后的流程,就是 TLS 握手(TLS Handshake)。它像两个陌生人第一次见面,互相确认身份、商量暗号、交换钥匙,然后才放心地开始交谈。
握手的目标
TLS 握手有三个主要目标:
- 协商加密算法:客户端和服务器都支持哪些加密算法?选一个双方都支持且最安全的。
- 身份认证:客户端确认服务器的身份(通过证书),防止中间人攻击。
- 生成会话密钥:安全地生成一个临时的对称密钥,用于后续加密传输。
整个过程涉及非对称加密(用于身份认证和密钥交换)和对称加密(最终用于数据加密),以及哈希函数(用于完整性校验)。
TLS 1.2 握手流程详解
下面我们以最常见的 TLS 1.2 为例,一步一步拆解握手过程。为了直观,我们配合一个简化的流程图来理解。
客户端(浏览器) 服务器(网站) |
第1步:ClientHello
客户端(浏览器)主动发起连接,发送一条 ClientHello 消息。这条消息包含:
- 客户端支持的 TLS 版本:比如 TLS 1.2、TLS 1.1 等。
- 一个随机数:称为
ClientRandom,用于后续生成密钥。 - 加密套件列表:客户端支持的所有加密算法组合,比如
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256表示用 ECDHE 做密钥交换、RSA 做证书签名、AES 128 GCM 做对称加密、SHA256 做哈希。 - 扩展字段:如服务器名称指示(SNI),告诉服务器要访问哪个域名(因为一个服务器可能托管多个网站)。
此时所有消息都是明文的,因为还没有任何加密。
第2步:ServerHello + Certificate
服务器收到 ClientHello 后,回复 ServerHello,其中包含:
- 选择的 TLS 版本(从客户端支持的版本中选一个)。
- 另一个随机数:
ServerRandom。 - 选择的加密套件(从客户端列表中选一个)。
紧接着,服务器发送自己的 数字证书(Certificate)。证书里包含了服务器的公钥以及网站的身份信息,由 CA 签名。
最后,服务器发送 ServerHelloDone 表示自己的初始消息发送完毕。
此时,客户端已经收到了服务器的证书。它会验证证书的有效性:检查域名、有效期、证书链等。如果验证失败,浏览器会显示警告,并中断连接。
第3步:ClientKeyExchange
客户端确认证书有效后,生成一个 预主密钥(Pre-master Secret)。这是一个临时生成的随机数,长度与加密算法相关(比如 RSA 密钥交换时为 48 字节)。然后,客户端用服务器的公钥加密这个预主密钥,通过 ClientKeyExchange 消息发送给服务器。
由于只有服务器拥有对应的私钥,因此只有它能解密得到预主密钥。任何窃听者都无法解密,因为公钥加密的内容只能用私钥解密。
第4步:计算会话密钥
现在,双方都拥有了三个素材:
ClientRandomServerRandomPre-master Secret
它们通过一个称为 密钥导出函数(KDF,Key Derivation Function)的算法,分别计算出相同的 会话密钥(Session Key)。这个会话密钥通常是一个对称密钥,用于后续加密数据。根据加密套件,还可能导出其他密钥,比如用于校验的 MAC 密钥。
此时,非对称加密的使命已经完成,接下来的通信将全部使用对称加密,速度快得多。
第5步:ChangeCipherSpec + Finished
客户端发送 ChangeCipherSpec 消息,告诉服务器:“从现在开始,我会用刚刚算出的会话密钥加密后续消息。”紧接着,客户端发送 Finished 消息,这是第一条加密的消息,内容是对整个握手过程(所有之前交换的消息)的哈希值,用于验证握手没有被篡改。
服务器收到后,同样回复 ChangeCipherSpec 和自己的 Finished 消息,也用会话密钥加密。客户端验证服务器的 Finished 消息后,握手正式完成。
第6步:应用数据
此后,所有 HTTP 请求和响应(网页、图片、表单数据等)都通过会话密钥进行对称加密,安全地传输。
关键点:为什么这样安全?
- 身份认证:通过证书,客户端确认了服务器的身份,防止冒充。
- 密钥交换:预主密钥用服务器公钥加密,只有服务器能解密,保证了密钥的机密性。
- 随机数:客户端和服务器各自贡献一个随机数,防止重放攻击(攻击者无法复用之前的握手)。
- 完整性:
Finished消息使用了整个握手的哈希,任何篡改都会被发现。
TLS 1.3 的简化
TLS 1.2 虽然广泛使用,但握手需要两次往返(2-RTT)。为了提高性能,TLS 1.3 进行了大幅简化,将握手减少到一次往返(1-RTT)。它去掉了复杂的加密套件组合,固定使用安全的算法,并把很多消息合并发送。更重要的是,TLS 1.3 强制要求前向保密(如 ECDHE),使得即使服务器的长期私钥泄露,也无法破解过去的会话。
当你看到小锁时
现在你知道了,那把锁不是凭空出现的。在你输入网址后的短短几百毫秒里,浏览器和服务器已经完成了一轮精心设计的密码学对话:它们交换了随机数,验证了身份,协商了加密算法,生成了只有双方知道的会话密钥。然后,所有的网页内容、图片、表单,都被这个密钥加密,在互联网的汪洋大海中安全地漂流,直到抵达你的屏幕。
这,就是现代互联网安全的基石。