TLS协议
概述
SSL 即安全套接字层,它位于 OSI 网络模型中的传输层,SSL 在 1999 年更名为 TLS ,即传输安全层,直到现在,TLS 一共出现过三个版本,1.1、1.2 和 1.3 ,目前最广泛使用的是 1.2,所以接下来的探讨都是基于 TLS 1.2 的版本上的。
设计目标
- 保密性
通过加密算法保护数据内容,防止敏感信息被窃听或截获。 - **完整性
通过校验机制检测数据是否在传输过程中被篡改。 - 身份认证
利用数字证书验证通信双方的身份,防止伪装和冒充。
使用场景
- HTTPS 协议: HTTP 通信接口部分由 SSL 和 TLS 替代而已。通常情况下,HTTP 会先直接和 TCP 进行通信。在使用 SSL 的 HTTPS 后,则会先演变为和 SSL 进行通信,然后再由 SSL 和 TCP 进行通信。也就是说,HTTPS 就是身披了一层 SSL 的 HTTP。
- 电子邮件传输:如 SMTP、IMAP 和 POP3。
- 文件传输:如 FTP over TLS (FTPS)。
- 即时通讯:如基于 TLS 的聊天和视频通话应用。
- 虚拟专用网络 (VPN):通过 TLS 隧道保护数据。
TLS协议分层

TLS Record协议
概述
- 安全服务
- Confidentiality
- Integrity
- 基于握手协议协商确定的安全参数对应用数据传输提供保密性和完整性保护
- 分片,压缩,加密,MAC
功能目标
- 消息传输
记录协议传输由上层协议提交给它的数据缓冲区,如果缓冲区超过长度限制(2^14),则需分片。属于同一协议的小缓冲区也可组合成单个记录。 - 加密及完整性验证
按照握手协议协商的安全参数进行加密和完整性验证(少量密码套件不加密仅完整性验证)。 - 压缩
设计上,记录协议在加密之前需要对数据进行压缩,以提高传输效率。
实践中,基本都没有实现压缩功能。 - 扩展性
记录协议只关注数据加密和传输,其余功能由其它子协议完成, 这种设计使得TLS协议具有很好的扩展性,可以根据需要添加子协议,所有子协议都会受到协商出的安全参数保护。
流程
- 明文分片
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
- 压缩
struct {
ContentType type;
ProtocolVersion version
uint16 length;
opaque fragment[TLSCompressed.length];
} TLSCompressed
- 安全处理
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
select (SecurityParameters.cipher_type) {
case stream: GenericStreamCipher;
case block: GenericBlockCipher;
case aead: GenericAEADCipher;
} fragment;
} TLSCiphertext;
struct {
opaque IV[SecurityParameters.record_iv_length];
block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length];
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
};
} GenericBlockCipher;
TLS Handshake协议
握手协议,用于在客户端和服务器之间协商产生用于记录协议中所要使用的密码算法和共享密钥, 基于证书的认证操作也在这个协议中完成。
对话过程
- 客户端:“你好。我能够支持的密码套件有RSA/3DES或者DSS/AES,我们使用哪个密码套件来通信呢?”
- 服务器端:“你才好呐。我们就用RSA/3DES来进行通信吧,这是我的证书。”
- 服务器端和客户端通过握手协议协商一致后,就会通过Change Cipher Spec Protocol来发出信号,切换到约定的密码规格。
-
HelloRequest
HelloRequest是一个简单的通知,告诉client应该重新开始一个协商过程。作为响应,client应该在合适的时候发送ClientHello消息。如果client当前正在协商一个会话,则该消息会被忽略。
-
ClientHello
- 在一次新的握手流程中,ClientHello消息总是第一条消息。ClientHello消息将客户端支持的功能和首选项发送给服务器。
- When: 发送ClientHello消息
- 在新建连接时
- 重新协商时
- 响应服务器发起的重新协商请求(HelloRequest)时
struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-2>;
CompressionMethod compression_methods<1..2^8-1>;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ClientHello;
压缩方法
extension
- Extension是TLS的一种扩展机制,可以在不修改协议本身的条件下为TLS协议增加功能。
- 扩展以扩展块的形式出现ClientHello和ServerHello消息的末尾
- 扩展块由所需数量的扩展一个个堆叠而成
- 扩展的格式和期望的行为由每个扩展自己决定,通常用于支持某些新功能、用于在握手阶段传递所需的额外参数。
- ServerHello
When:
当服务器收到来自客户端的ClientHello消息后,如果它能够找到一套可以接受的算法(即可以就加密算法等取得协商一致),服务器将发送ServerHello消息来响应客户端的ClientHello消息。
如果不能找到一套匹配的算法,则服务器将响应handshake failure alert。
struct {
ProtocolVersion server_version;
Random random;
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ServerHello;
-
Certificate
服务器向客户端发送Certificate消息,使得客户端能够认证服务器的身份。
匿名通信的情况下,服务器不需要发送certificate消息。
-
ServerKeyExchange
When:
服务器发送server Certificate消息后,立即发送ServerKeyExchange消息(如果是匿名协商,则在ServerHello后立即发送该消息)。
同时,仅当server Certificate消息包含的信息不足以让客户端交换一个premaster secret时,才发送ServerKeyExchange消息。 比如:DHE_DSS、DHE_RSA、DH_anon。
而对于密钥交换算法RSA、DH_DSS、DH_RSA,如果发送ServerKeyExchange消息则是非法。 -
CertificateRequest
服务器使用CertificateRequest消息请求对客户端进行身份验证,其中包含了服务器可以接受的证书类型列表,可接受的CA的列表。
-
ServerHelloDone
服务器发送ServerHelloDone消息来表示ServerHello及相关消息的结束,这些消息用于完成密钥交换,发送该消息后,服务器将等待客户端响应。
而客户端收到该消息后,可以继续他的密钥交换阶段。
ServerHelloDone消息不包含任何内容。 -
ClientKeyExchange
如果客户端发送了Client Certificate消息,ClientKeyExchange消息应该在该消息后立即发送。
否则,在客户端收到服务器发送的ServerHelloDone后立即发送该消息。
- 客户端发送ClientKeyExchange消息,向服务器提供用于生成对称加密密钥等所需的数据,相当于告诉服务器:“这是经过加密的Premaster secret。”
- 当密码套件包含RSA时,会随ClientKeyExchange消息发送经过RSA-encrypted的premaster secret。
- 当密码套件包含Diffie-Hellman密钥交换时,会随ClientKeyExchange消息发送Diffie-Hellman的公开值。
-
CertificateVerify
只有服务器向客户端发送CertificateRequest消息的情况下,客户端才会向服务器发送CertificateVerify消息,以向服务器证明自己的确持有客户端证书的私钥。 -
Fininshed
- When:
发送ChangeCipherSpec来激活已经协商好的密码套件之后,客户端发送Finished消息,表明TLS握手协商完成,相当于告诉服务器“握手结束。” - 密文 ? 明文:
由于已经完成了密码规格切换,因此Finished消息是使用切换后的密码套件来发送的,也就是Finished消息不是以明文方式发送的,而是通过下层的记录协议进行加密发送。 - Finished消息的内容采用PRF函数生成,其输入包括:master_secret, finished_label,之前所有handshake消息组合的hash值。
- 服务器可以通过对收到的消息进行验证来确认收到的Finished消息是否正确,从而可以确认握手协议是否正常结束,密码套件的切换是否正确。
- Finished消息:防止降级攻击
- 什么是降级攻击?
MiTM攻击者修改ClientHello消息里面的密码套件列表,用较弱的密码套件替换较强的密码套件,从而降低所建立的通信信道的安全性。 - Finished消息,包含了所有握手消息的hash,如果攻击者篡改前面的握手消息,则无法通过验证。
- 什么是降级攻击?
ChangeCipherSpec Protocol
Alert Protocol
概述
以简单的通知机制告知通信对端出现异常状况
- 报告错误
- 通知连接关闭
struct {
AlertLevel level;
AlertDescription description;
} Alert;
AlertLevel
-
Alert消息分两类:警告消息(warning )和致命消息(fatal )。
-
致命消息将导致连接被立即中止,并将与这个连接相关的会话(SessionID)作废,以免这个会话被继续用来建立新的连接。
-
警告消息仅仅是通告对方有关报警信息,不会导致连接的关闭。
-
TLS报警消息类型与触发原因如下
-
Alert消息 封装
Closure alert(关闭连接警报)
- 一旦一端确定无数据发送,决定关闭连接,就会发送一个close_notify警报。另一端收到这个警报后,会丢弃任何还未写出的数据,并发送自己的close_notify警报。警报之后的任何消息都会被忽略。
- 目的:防止truncation attack(截断攻击)
- 攻击者主动发送TCP FIN包,提前结束通信,阻断后续消息的发送。
- 如果没有close_notify警报功能,通信双方无法确定是被攻击了还是通信真正结束了。