TLS协议梳理
最后更新于
最后更新于
TLS协议分为上层协议和下层协议,上层协议包含握手协议,警报协议,应用数据协议,下次为记录层协议(Record Layer Protocol),记录层协议的主要作用如下
分片: 将上层协议的数据分割成合适大小的块,每个块最大不超过 16KB
封装: 为每个数据块添加头部信息,标识数据类型、协议版本和长度
加密: 对每个数据块进行加密,确保数据传输的安全性
记录层协议头格式
每个 TLS 记录都以 5 字节的头部开始:
类型(Type): 1 字节
0x16: Handshake (握手)
0x17: Application Data (应用数据)
0x15: Alert (警告)
版本号(Version): 2 字节
0x0301: TLS 1.0
0x0302: TLS 1.1
0x0303: TLS 1.2/1.3
长度(Length): 2 字节
表示后续数据的长度
示例:
0x16: 表示这是握手消息
0x0301: 表示 TLS 1.0 记录层版本
0x014a: 表示后续数据长度为 330 字节
注意:
TLS记录层协议的版本可以与握手协议中使用的版本不一致,这是TLS 1.3中的一个特别设计。这种设计主要是为了确保向后兼容性,让支持TLS 1.3的通信在网络中的其他设备(比如中间的代理或防火墙)仍然能够以TLS 1.2的方式处理TLS记录,即使实际的握手和数据传输使用的是TLS 1.3。
在TLS 1.2及之前的版本中,记录层的版本号通常与握手使用的版本相匹配。但在TLS 1.3中,为了改进安全性和性能同时避免中间设备的干扰,引入了以下变化:
记录层版本号:
在TLS 1.3中,所有传出的记录(无论是握手还是数据传输)的版本号都被设定为0x0303
(即TLS 1.2),即使实际的握手使用的是TLS 1.3。
握手协议的版本:
握手协议的真正版本是通过ClientHello
和ServerHello
消息中的supported_versions
扩展来指定的。这个扩展允许客户端和服务器协商实际要使用的最高TLS版本,包括TLS 1.3。
握手阶段涉及的加密算法
基本原理:私钥加密,公钥验证
RSA(Rivest-Shamir-Adleman)算法
对应RSA证书
兼容性好,广泛使用
密钥长度长,性能一般,常见密钥长度: 2048位(当前最低推荐长度), 3072位, 4096位(更高安全性)
签名填充方案对比
用途
数字签名
数字签名
安全性
较弱(缺乏可证明安全性)
强(可证明安全)
填充结构
sd
使用盐值和MGF
随机性
确定性(相同消息产生相同签名)
概率性(相同消息产生不同签名)
现代协议支持
广泛支持(传统系统)
TLS 1.3唯一支持的RSA方案
性能
较快
较慢
推荐使用
仅用于兼容性
推荐
ECDSA(Elliptic Curve Digital Signature Algorithm)算法
对应ECC证书
是一种基于椭圆曲线的数字签名算法
性能好,密钥长度短,适合移动设备、物联网设备等资源受限环境下的应用场景
PSK(Pre-Shared Key)
最简单的方式双方提前约定好密钥,后续通信时直接使用这个密钥
TLS1.3中的PSK指的是上次连接生成的PSK,客户端保存后,用于下次0RTT传输
RSA
使用RSA算法进行密钥交换, 客户端使用公钥加密,服务端使用私钥解密
加密填充方案对比
用途
数据加密
数据加密
安全性
较弱(易受Bleichenbacher攻击)
强(可证明安全)
填充结构
使用双重掩码(MGF)
随机性
部分随机(PS部分)
完全随机
现代协议支持
逐渐淘汰
广泛支持
性能
较快
较慢
推荐使用
不推荐
推荐
RSA 模式有一个严重的缺点:它不是前向保密的。这意味着如果有人记录了加密的对话,然后获取了服务器的 RSA 私钥,他们就可以解密对话。即使对话是在很久以前记录的,而密钥是在未来某个时间获得的,这也适用
tls1.3中不再支持RSA密钥交换算法
DH(Diffie-Hellman)
DH基于大整数分解问题(Discrete Logarithm Problem),DH协议允许通信双方在不安全的通信通道上协商一个共享的对称密钥,DH生成的密钥通常是长期有效的,它不是前向保密的
客户端和服务器首先各自创建一个公私钥对。然后,它们将公钥部分发送给对方。当每一方收到对方的公钥部分后,将其与自己的私钥结合,最终得到相同的值:预主密钥
原理可以想象成调配颜料的过程:
爱丽丝和鲍勃先约定使用黄色作为基础颜色(公钥)
爱丽丝秘密选择红色,鲍勃秘密选择蓝色(这是各自的私钥)
爱丽丝将黄色+红色混合,把结果发给鲍勃(KeyExchange)
鲍勃将黄色+蓝色混合,把结果发给爱丽丝(KeyExchange)
爱丽丝将收到的(黄+蓝)再加入红色
鲍勃将收到的(黄+红)再加入蓝色
最终双方都得到了相同的紫色(黄+红+蓝),这就是共享密钥
Diffie-Hellman 的安全性依赖于一个称为离散对数问题的特定数学难题的难度。如果能为一组参数解决离散对数问题,就可以提取私钥并破坏协议的安全性。一般来说,使用的数字越大,解决离散对数问题就越困难。因此,如果选择了较小的 DH 参数,则可能存在安全风险。TLS 1.3 取消了这一选择权,只保留了几种固定的DH参数,这些参数是经过广泛测试和验证的,安全性较高
DHE(Diffie-Hellman Ephemeral)
DHE是DH的改进版本,DHE生成的密钥是临时有效的,每次握手都会生成新的密钥,提供前向安全性
ECDH(Elliptic Curve Diffie-Hellman)
ECDH是基于椭圆曲线密码学的密钥交换协议,和DH原理基本相同,在相同的密钥强度下比DH更加高效。ECDH生成的密钥通常是长期有效的,因此安全性依赖于长期保持私密性
ECDHE(Elliptic Curve Diffie-Hellman Ephemeral)
ECDHE是ECDH的改进版本,ECDHE生成的密钥是临时有效的,每次握手都会生成新的密钥,提供前向安全性
关于静态密钥和临时密钥
服务端证书包含固定DH参数,客户端使用使用证书中的参数,双方计算共享密钥,每次会话都使用相同的参数,称为静态密钥
服务端生成新的DH参数,将参数发送给客户端,客户端生成自己的密钥对,双方交换公钥并计算共享密钥,每次会话都使用新的DH参数
TLS1.3不再支持静态密钥交换算法,只支持临时密钥交换算法,包括ECDHE,有限DHE, 所有的密钥交换算法都提供前向安全性. 支持的身份验证算法为: RSA-PSS(最小密钥长度2048位),ECDSA,EdDSA
握手成功后,客户端使用对称加密算法加密,服务端解密
对称密码分为两种主要形式:
流密码(Stream Cipher)
工作原理:
使用固定大小的密钥生成任意长度的密钥流(伪随机数据流)
加密时将消息与密钥流按位异或
解密时将密文与密钥流按位异或
工作原理详解:
加密和解密过程:
加密: 明文 P 与密钥 K 进行异或操作,生成密文 C :
C = P ⊕ K
解密: 密文 C 与密钥 K 再次异或,恢复明文 P :
C ⊕ K = (P ⊕ K) ⊕ K = P ⊕ (K ⊕ K) = P ⊕ 0 = P
异或操作的核心特性:
自反性: A ⊕ A = 0
任何值与自身异或结果为0
与0的关系: A ⊕ 0 = A
任何值与0异或结果是其本身
可逆性: (A ⊕ B) ⊕ B = A
异或操作可逆,两次异或同一个值会恢复原始值
举例说明:
明文 P = 1010
密钥 K = 1100
加密: C = P ⊕ K = 1010 ⊕ 1100 = 0110
解密: P = C ⊕ K = 0110 ⊕ 1100 = 1010
特点:
实现简单
软件中运行速度快
适合实时加密
代表算法:
RC4
ChaCha20
分组密码(Block Cipher)
工作原理:
只能加密固定大小的数据块
对于短于分组大小的消息需要填充
对于长于分组大小的消息需要分块处理
CBC模式工作原理:
加密过程:
将明文分成固定大小的块(如128位)
生成随机的初始化向量(IV)
对每个明文块:
将当前明文块与前一个密文块(或IV)进行异或
对异或结果进行加密,得到当前密文块
将所有密文块连接形成完整密文
解密过程:
将密文分成固定大小的块
对每个密文块:
对当前密文块进行解密
将解密结果与前一个密文块(或IV)异或,恢复明文块
将所有明文块连接形成完整明文
举例说明:
假设使用AES-128加密:
明文: HELLO WORLD!1234
(16字节)
密钥: 0123456789ABCDEF
(16字节)
IV: FEDCBA9876543210
(16字节)
加密过程:
明文块与IV异或: HELLO WORLD!1234 XOR FEDCBA9876543210 = 结果1
对结果1进行AES加密得到密文块
解密过程:
对密文块AES解密得到结果1
结果1与IV异或: 结果1 XOR FEDCBA9876543210 = HELLO WORLD!1234
特点:
需要初始化向量(IV)
每个明文块的加密依赖于前一个密文块
需要填充(Padding)确保明文长度是分组大小的整数倍
通过链式结构增强加密随机性和安全性
常用模式:
CBC(Cipher Block Chaining)模式
每个明文块先与前一个密文块异或后再加密
代表算法:
AES
DES
3DES
散列函数的特性
无法从散列值反推原文
难以找到两个不同的输入产生相同的散列值
固定长度输出
散列函数在TLS中主要用于:
数字签名生成和验证
签名时使用散列的原因是:
哈希值长度固定,处理更快
减少签名运算的数据量
适合任意长度的输入数据
保证数据完整性
克服了RSA等算法的长度限制
消息认证码(HMAC)生成
提供消息完整性和认证
配合时间戳和过期机制可以防止重放攻击
MAC-then-Encrypt 和 Encrypt-then-MAC
MAC-then-Encrypt(TLS1.2及以前):
先计算明文的MAC,再加密明文和MAC
存在安全隐患:
接收方需要先解密才能验证MAC
容易受到填充oracle攻击(如POODLE)
MAC验证滞后,攻击者可在解密过程中攻击
Encrypt-then-MAC(TLS1.3):
先加密明文,再计算密文的MAC
更安全的原因:
接收方先验证MAC,确保密文未被篡改
MAC验证失败直接拒绝,无需解密
避免了填充oracle攻击
举例说明
假设明文为HELLO,密钥为KEY_ENC和KEY_MAC
MAC-then-Encrypt流程:
计算MAC: MAC(HELLO)得到MAC_HELLO
拼接: HELLO || MAC_HELLO
加密得到密文
Encrypt-then-MAC流程:
加密HELLO得到密文
计算密文的MAC
发送密文||MAC
伪随机数生成
密钥导出
常见的散列函数包括:
MD5(已不安全,不推荐使用)
SHA-1(已不安全,不推荐使用)
SHA-2家族(SHA-256/384/512)
SHA-3家族
密钥交换
通过RSA或Diffie-Hellman等密钥交换算法生成预主密钥(Pre-Master Secret)
生成主密钥
使用预主密钥、客户端随机数和服务器随机数
通过PRF(基于HMAC-SHA256的伪随机函数)生成主密钥(Master Secret)
派生会话密钥 从主密钥中派生出用于加密和完整性检查的密钥块,包括:
客户端写加密密钥(Client Write Encryption Key)
服务器写加密密钥(Server Write Encryption Key)
客户端写MAC密钥(Client Write MAC Key)
服务器写MAC密钥(Server Write MAC Key)
加密模式(如CBC)所需的IV(初始化向量)
应用数据密钥
Client Application Traffic Secret
Server Application Traffic Secret
特殊用途密钥
Resumption Master Secret (会话恢复主密钥))
用途:
生成 PSK (Pre-Shared Key),用于下一次连接
支持会话恢复
启用 0-RTT 数据传输
Early Exporter Master Secret (早期导出主密钥)
用途:
Early Exporter Master Secret 是保护 0-RTT 数据的工具
它在 0-RTT 传输过程中使用,提供额外的安全保证
Exporter Master Secret (用于外部密钥导出)
用途
为外部协议提供密钥材料
支持协议绑定
派生额外的密钥
X.509 是密码学里公钥证书的格式标准,证书中主要包含以下信息:
版本号:证书采用的X.509标准版本
序列号:由CA分配的唯一标识符
签名算法:用于签发证书的算法(如RSA、ECDSA等)
颁发者信息:颁发证书的CA机构信息
国家(C, Country)
组织(O, Organization)
组织单位(OU, Organization Unit)
通用名称(CN, Common Name)
有效期:证书的生效时间和过期时间
主体信息:证书持有者的信息
国家(C)
省/州(ST, State)
地区(L, Locality)
组织(O)
组织单位(OU)
通用名称(CN)
公钥信息:
公钥算法
公钥长度
公钥值
扩展信息:
密钥用途
主体备用名称(SAN)
CRL分发点
基本约束
服务端管理员生成一对公钥和私钥,服务端将公钥和申请信息(域名,申请者信息)等发送给CA机构
CA机构核实服务端拥有着的信息,如组织是否存在、企业是否合法、是否拥有域名的所有权等
核实无误后,CA机构使用自己的私钥对证书中的所有信息(版本号、序列号、签名算法、颁发者信息、有效期、主体信息、公钥信息、扩展信息等)进行签名
客户端在和服务端进行TLS握手时,服务端会将证书发送给客户端
客户端首先检查证书的有效期、域名是否匹配等基本信息
然后客户端会使用证书中的签名算法(在证书的签名算法字段中指定)和CA公钥来验证证书签名
验证过程:
提取证书中除签名外的所有信息,使用相同的签名算法计算摘要
使用CA公钥验证证书中的签名,得到原始摘要
比较两个摘要是否一致,一致则说明证书确实是由该CA签发且未被篡改
RSA签名验证
首先验证服务器证书,使用中间证书的公钥验证服务器证书的签名
然后验证中间证书,使用根证书的公钥验证中间证书的签名
根证书是预先内置在系统/浏览器中的可信证书,不需要再验证
只有整个证书链都验证通过,才能确认服务器证书的可信性
验证通过后,客户端才会信任该服务器证书,继续后续的TLS握手过程
简单概括: 权威机构使用自己的私钥将主体信息加密成证书,客户端使用权威机构的公钥验证,通过则说明证书可信
安全性:
根证书是整个PKI体系的信任源,需要严格保护,通常离线存储
使用中间证书可以保护根证书私钥,即使中间证书私钥泄露,根证书仍然安全
灵活性:
可以为不同业务场景颁发不同的中间证书
中间证书出现问题时,可以单独吊销而不影响其他证书
效率:
根证书离线存储导致签发证书效率低
中间证书可以在线运行,提高证书签发效率
证书管理:
可以通过中间证书将证书层级化管理
便于证书的分类和权限控制
TLS 证书的文件后缀名并不重要,TLS 证书可以以纯文本形式存储(这是最常见的形式,适用于 Linux、Apache、Unix 和其他服务器),也可以以二进制形式存储(如 Java、Microsoft Server),证书以纯文本形式保存为 Base64 编码,二进制文件无法用文本编辑器打开
PEM
这是最常用的证书存储格式。我们通常将 PEM 称为"文本格式",它是以 Base64 编码的。
PEM 是使用 ASCII 字母的 Base64 编码文件,PEM格式的文件使用Base64编码,并且通常以-----BEGIN ...-----和-----END ...-----包围起来,用来标识不同的部分。
DER
DER 格式是一种二进制证书格式。它不是文本,无法像文本一样打开阅读或复制。这是与 Base64 的主要区别。
所有证书类型和私钥都可以存储为 DER 格式,DER 格式用于 Java 平台。
CRT和CER 通常用于存储证书
KEY 通常用于存储私钥
PEM 可以仅包含证书、私钥或两者都有
使用openssl可以将der编码的证书转换为pem编码的证书:
使用openssl可以将私钥(原始私钥格式)转换为pem编码的私钥:
使用openssl可以将pem编码的证书和私钥组合在同一个pem文件中:
[]表示可选或者有条件的消息
*表示可以发送0个或多个该类型的消息
ClientHello: 客户端向服务器发送客户端生成的随机数,可能的会话ID,支持的最高SSL版本,支持的加密套件列表,加密套件信息包括加密算法和密钥大小。
ServerHello: 服务器选择客户端和服务器都支持的最高SSL版本(例如,如果客户端支持 TLS 1.1 版本,而服务器支持 1.2 版本,则应选择 1.1 版本;不应选择 1.2 版本。),最佳加密套件,以及服务端生成的随机数,可能的会话ID,并将此信息发送给客户端。
Certificate(可选): 服务器向客户端发送证书或证书链。证书链通常以服务器的公钥证书开始,以证书颁发机构的根证书结束。此消息是可选的,根据选择的身份验证算法,可能需要证书。
CertificateRequest(可选): 如果服务器必须验证客户端身份,则向客户端发送证书请求。在互联网应用中这种情况很少见。
ServerKeyExchange(可选): 根据选择的密钥交换算法,服务器可能会向客户端发送服务器密钥交换消息。
ServerHelloDone: 服务器告诉客户端已完成初始协商消息。
Certificate(可选): 如果服务器请求客户端证书,客户端会发送其证书链,与服务器之前的操作类似。
ClientKeyExchange: 客户端生成用于对称加密的密钥信息,对于RSA,客户端从服务器的 SSL 证书中获取公钥加密此密钥信息(预主密钥)并发送给服务器。对于DH系列的加密套件,此消息包含客户端的DH相关参数。
CertificateVerify(可选): 当客户端提供证书时发送此消息。其目的是让服务器完成客户端身份验证过程。客户端使用加密哈希函数对信息进行数字签名,服务器用客户端公钥解密此信息来验证客户端身份。
ChangeCipherSpec: 客户端发送消息告诉服务器切换到加密模式,后续数据传输使用协商的对称加密算法和密钥进行加密。
Finished: 客户端告诉服务器已准备好开始安全数据通信。
ChangeCipherSpec: 服务端发送消息告诉客户端切换到加密模式,后续数据传输使用协商的对称加密算法和密钥进行加密。
Finished: 服务端告诉客户端已准备好开始安全数据通信。这标志着SSL握手的结束。
加密数据传输: 客户端和服务器使用在ClientHello和ServerHello期间协商的对称加密算法和加密哈希函数,以及客户端在ClientKeyExchange期间发送给服务器的密钥进行通信。此时可以重新协商握手。
注意:
ClientHello 会发送会话 ID或ticket。但对于新连接,会话 ID或ticket 为空。只有在尝试恢复之前的会话时,才会发送非空的会话 ID或ticket。这是为了支持会话恢复(Session Resumption)机制
在 RSA 握手中,预主密钥由客户端生成的随机数据组成。在 DH系列算法中,客户端和服务器使用商定的参数分别计算相同的预主密钥。
ServerKeyExchange和ClientKeyExchange不同算法的区别
RSA
不需要
加密的预主密钥
不提供前向安全性 实现简单 计算开销较大
传统系统 简单部署场景
DHE/ECDHE
必需: DH/ECDH参数 临时公钥 参数签名
客户端临时公钥
完美前向安全性 每次会话新密钥 最高安全级别
现代HTTPS 高安全需求场景
DH/ECDH(静态)
条件发送: 证书含参数则不需要 证书不含则需要
客户端公钥
有限前向安全性 密钥复用
特定应用场景 性能优先场景
ClientHello请求细节
向服务器发送了自己支持的加密套件
支持的椭圆曲线
支持的多种签名算法
ServerHello请求细节
服务器选用的加密套件为TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
使用 ECDHE 进行密钥交换
因为使用ECDHE进行密钥交换,在tls1.2中会有专门的ServerKeyExchange 和 ClientKeyExchange阶段
RSA 用于认证
AES-128-GCM 用于加密
SHA256 用于哈希
流程解读:
ClientHello: 客户端发送支持的加密套件列表、key_share扩展(包含客户端的ECDH公钥)等信息
ServerHello: 服务器选择加密套件,并在key_share扩展中发送自己的ECDH公钥,如果服务端不支持客户端的加密算法,则发送HelloRetryRequest通知
在TLS 1.3中,keyShare
是客户端和服务器在密钥交换过程中发送的临时公钥(通常是椭圆曲线公钥或Diffie-Hellman公钥)。这个公钥用于生成共享密钥(Pre-Master Secret),但它本身并不使用私钥进行签名。这是因为keyShare
的目的是为了密钥交换,而不是身份验证。身份验证是通过其他机制(如certificateVerify
)来完成的。
EncryptedExtensions(可选): 服务器发送加密的扩展数据
CertificateRequest(可选): 如果需要客户端认证,服务器发送证书请求
Certificate(可选): 服务器发送证书链
CertificateVerify(可选): 服务器使用私钥对之前的握手消息进行签名
CertificateVerify消息的作用是证明发送方持有证书中公钥对应的私钥,具体实现如下:
握手消息哈希计算
记录从ClientHello到CertificateVerify之前的所有握手消息
计算这些消息的哈希值(通常使用SHA-256等),称为握手上下文哈希
签名内容构造
签名内容格式为: "TLS 1.3, certificate verify" + 0x00 + 握手上下文哈希
固定字符串用于区分签名用途
私钥签名
使用私钥对构造的内容进行签名(RSA-PSS/ECDSA等)
将签名放入CertificateVerify消息中发送
接收方验证
重新计算握手消息哈希值
使用发送方证书公钥验证签名
验证签名内容是否匹配预期格式
安全保证
只有持有私钥才能生成有效签名
签名包含所有握手消息哈希,防止篡改
确保了不可抵赖性和完整性
Finished: 服务器发送验证数据,确认握手完成
Finished消息的作用和实现
作用:验证握手过程的完整性,确保消息未被篡改
基于HMAC(Hash-based Message Authentication Code)实现
HMAC的输入包括:
握手上下文哈希:从ClientHello到Finished之前所有消息的哈希值
固定字符串:
客户端使用"client finished"
服务器使用"server finished"
HMAC密钥:
从主密钥(Master Secret)通过HKDF派生
分别生成客户端和服务器的finished密钥
HMAC计算:
验证流程:
接收方重新计算握手消息哈希值
使用finished密钥验证HMAC
比较计算值与接收值是否一致
不一致则终止连接
安全保证:
只有持有正确密钥才能生成/验证HMAC
任何消息篡改都会导致验证失败
有效防止中间人攻击
Certificate(可选): 如果服务器请求了客户端证书,客户端发送证书
CertificateVerify(可选): 如果发送了客户端证书,客户端对握手消息签名
Finished: 客户端发送验证数据,确认握手完成
上图使用wireshark对curl https://www.example.com
握手过程进行抓包
实际握手举例:
上图使用wireshark对curl https://www.example.com
握手过程进行抓包
服务器返回Hello Retry Request 的原因是服务端未接受客户端第一次发送的加密算法,对比两次Client Hello 请求
第二次ClientHello请求细节
向服务器发送了自己支持的加密套件
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256
支持的椭圆曲线
支持的多种签名算法
在Extension: key_share
中设置使用secp256r1椭圆曲线进行密钥交换,并且发送自己的ECDH公钥值
ServerHello请求细节
使用的加密套件为TLS_AES_256_GCM_SHA384
在Extension: key_share
中设置使用secp256r1椭圆曲线进行密钥交换,并且发送自己的ECDH公钥值
Session ID(TLS1.2):
在首次完整 TLS 握手时,服务器生成一个唯一的 Session ID 并与会话相关的密钥材料(如主密钥、加密套件等)一起存储在服务器端;当客户端再次连接时,通过在 ClientHello 消息中携带之前获得的 Session ID,服务器检查并找到对应的会话信息后,双方就可以直接重用之前协商的密钥材料,从而跳过证书验证和密k钥交换等步骤,大大减少了握手往返次数和计算开销。
Session Ticket(TLS1.2):
服务器不再存储会话状态,而是在首次握手完成时,将会话信息(包括主密钥、加密套件等)用票据加密密钥(Ticket Encryption Key)加密后,以票据(Ticket)的形式发送给客户端保存;当客户端再次连接时,将保存的票据在 ClientHello 中发回服务器,服务器使用相同的票据加密密钥解密该票据以恢复会话状态,从而实现无状态的会话复用,这种机制特别适合需要横向扩展的大规模部署场景
PSK(TLS1.3):
在 TLS 1.3 中,ID和Ticket的方式已经被弃用,使用PSK方式
PSK(Pre-Shared Key)会话恢复机制的工作原理是:当首次完整 TLS 握手完成时,服务器会生成一个包含会话参数的加密票据(ticket)发送给客户端保存,在后续连接中,客户端可以在 ClientHello 消息中携带这个 PSK 标识符,如果服务器验证有效,双方就可以使用这个预共享密钥(配合新的 (EC)DHE 密钥交换)快速建立安全连接,从而避免了完整的握手过程,同时保证了前向安全性。
优点:
安全性更高,强制与 (EC)DHE 结合使用,提供完美前向保密(PFS)
握手过程更简化,支持 0-RTT 数据传输
扩展性更好,无需跨服务器同步状态,适合分布式系统部署,更容易实现负载均衡
TLS1.2如何确定使用的哪种方式
在TLS1.2中 通过观察 TLS 握手过程中的数据包特征可以确定使用的复用机制:如果看到 ClientHello 中包含非空的 Session ID 且 ServerHello 返回相同的 Session ID 进行复用,则是使用 Session ID 机制;如果看到 ClientHello 中包含 session_ticket 扩展并携带之前的票据,且在握手过程中出现 NewSessionTicket 消息,则是使用 Session Ticket 机制;此外,虽然客户端可能同时支持两种机制,但最终使用哪种取决于服务器的选择和响应。
1 RTT
客户端发送 ClientHello 消息,包含:
pre_shared_key 扩展,包含之前获得的 PSK 标识符
key_share 扩展,用于 (EC)DHE 密钥交换
服务器响应:
验证 PSK 有效性
发送 ServerHello,包含选中的 PSK 和 key_share
发送 EncryptedExtensions
发送 Finished 消息
客户端发送 Finished 消息
握手完成,双方可以开始交换加密的应用数据
0 RTT
客户端发送 ClientHello 消息,包含:
early_data 扩展,表明要发送 0-RTT 数据
early_data代表在TLS握手完成之前发送的数据
key_share 扩展,用于密钥交换
pre_shared_key 扩展,包含之前会话的 PSK
psk_key_exchange_modes 扩展,指定 PSK 密钥交换模式
可以立即发送加密的应用数据(0-RTT 数据)
服务器响应:
验证 PSK 有效性
发送 ServerHello,包含:
pre_shared_key 扩展,确认使用的 PSK
key_share 扩展,用于密钥交换
发送 EncryptedExtensions,包含:
early_data 扩展,表明接受 0-RTT 数据
发送 Finished 消息
可以开始发送加密的应用数据
客户端:
发送 EndOfEarlyData 消息,表明 0-RTT 数据发送完成
发送 Finished 消息
握手完成,双方可以继续交换加密的应用数据
注意事项:
0-RTT 数据可能被重放,需要应用层防重放机制
服务器可以拒绝 0-RTT 数据,此时需要完整 1-RTT 握手
0-RTT 仅支持部分加密套件和应用数据