TLS1.2 和 TLS1.3的简要区别
一 TLS发展历史:
SSL(Secure Socket Layer) / TLS(Transport Layer Security) 是独立于 HTTP 的协议,所以不光是 HTTP 协议,其他运行在应用层的 SMTP 和 Telnet 等协议均可配合 SSL / TLS 协议使用,可以说 SSL / TLS 是当今世界上应用最为广泛的网络安全技术。
Netscape 开发了原始的 SSL 协议:
SSL 1.0 因为存在严重的安全缺陷从未公开发布
SSL 2.0于 1995年发布,但其中仍包含许多安全缺陷
SSL 3.0在1996年发布了。随着加密与解密安全攻防战的博弈,SSL 协议的安全性逐渐满足不了需求
SSL 2.0 在 2011 年被RFC 6176弃用
SSL 3.0 于 2015 年被RFC 7568弃用。
TLS的发展历程:
TLS 1.0 在 1999 年发布于RFC 2246中,TLS 1.0 和 SSL 3.0 之间的差异并不显著(TLS 1.0 等同于 SSL 3.1),改名主要是为了和Netscape撇清关系(TLS协议由 IETF 进行标准化)
TLS 1.1 于 2006 年在RFC 4346中定义
TLS 1.2 于 2008 年在RFC 5246中定义,并于2011年在RFC 6176中完成优化
TLS 1.3 于 2018 年在RFC 8446中定义。
早在2018年10月,苹果、谷歌、微软和Mozilla就联合宣布,将在2020年3月弃用TLS 1.0和TLS 1.1(当你读到本篇博客时,TLS 1.0和TLS 1.1 已经被弃用)
TLS 1.3 才发布没多久,未来几年内 TLS 1.2 将成为网络安全协议的主流(HTTP/2协议便使用TLS 1.2+版本作为安全加密层)。
二 TLS1.2 和 TLS1.3的主要差别:
TLS1.3的密钥协商速度要快于TLS1.2,特别是在曾经建立过连接的情况下,TLS1.3支持0- Round Trip Time快速恢复连接。
TLS1.3针对1.2支持的密钥交换方法和加密方法做了简化,删除了不安全的方法。TLS1.3支持的方法都具备前向安全性。
三 TLS1.2 和 TLS1.3的握手流程:
TLS1.2 的握手流程:
TLS 1.2 完整的握手过程(从发送第一个握手报文到发送第一个用户数据报文)需要在客户端与服务器之间完成两次往返通信,也即 2-RTT(Round Trip Time)
TLS 1.2 会快速恢复的过程
1.TLS 1.2握手过程ClientHello与ServerHello报文中的会话ID字段信息;
2.最初的会话恢复机制就是利用会话ID字段信息(由服务器在首次收到ClientHello握手报文后创建,并通过ServerHello握手报文传递给客户端)实现会话快速恢复的
3.客户端和服务器在TLS 连接断开后都会将会话的安全参数保存一段时间。
4.如果客户端想快速恢复会话,将对应的会话ID 通过ClientHello握手报文发送给服务器,服务器如果愿意恢复会话,就将相同的会话ID放入ServerHello消息返回
5.接着使用之前协商的主共享密钥生成一套新的共享密钥(为了前向保密,尽量做到每次会话使用不同的密钥),通信双方再通过ChangeCipherSpec报文约定变更到新的加密方式
6.最后通过Finished报文完成简短握手过程的完整性校验,后面就可以进行应用数据认证加密通信了。
TLS 1.2 会话恢复的简短握手过程从发送第一个报文ClientHello到发送应用数据,只需要一次网络往返 1-RTT
利用session-id恢复的缺点:
在分布式服务器中,多机之间往往没有同步 Session ID 信息,如果客户端两次请求没有落在同一台服务器上就无法找到匹配的信息;
服务器端存储 Session ID 对应的信息不好控制失效时间,太短起不到作用,太长又占用服务端大量资源
为了解决使用Session ID的问题,又引入了Session Ticket 作为新的会话恢复方案。
Session Ticket 是用只有服务器端知道的安全密钥加密过的会话信息(包含恢复会话所需的所有信息),由服务器端在完成完整的握手过程后生成New Session Ticket 并发送给客户端保存。如果客户端想快速恢复会话,可以将对应的Session Ticket 通过 ClientHello 报文发送给服务器,只要服务器能验证Session Ticket 的完整性,并成功解密其内容,就可以使用其中的信息快速恢复会话。
Session Ticket 与 Session ID 会话恢复方案的主要区别就是,Session Ticket 将会话恢复所需的信息保存在客户端(与HTTP Cookie的原理类似),Session ID 将会话恢复所需的信息保存在服务器端,当采用分布式服务器集群时,显然Session Ticket 是更合适的会话恢复方案(TLS 1.3 仅支持类似Session Ticket 的会话恢复方案)。
TLS1.3 的握手流程:
LS 1.3 废弃了RSA密钥交换方案(因为RSA不具有前向保密性),仅支持(EC)DHE密钥协商方案;
RSA密钥交换方案需要客户端先拿到服务器的公钥证书,使用服务器公钥来加密要发送的预备共享密钥,所以RSA密钥交换需要在第二个网络往返中交换共享密钥。
DHE密钥协商方案则没有这个限制,虽然理论上客户端也需要先拿到服务器提供的域参数(比如前篇博文介绍DHE中的G、P两个参数,或者ECDHE中的椭圆曲线类型)才能计算出自己的密钥协商参数(比如DHE中的Gc mod P),但这并非必要条件。客户端可以像发送支持的加密套件列表那样,向服务器发送支持的域参数组合列表(比如椭圆曲线类型列表)及其对应的密钥协商参数,服务器只需要从列表中选择一组确定为双方使用的域参数即可,这样就可以在第一个网络往返中协商共享密钥了。
TLS 1.3 可以在第一个网络往返中完成共享密钥协商和身份认证,在完成共享密钥协商和身份认证后可以直接切换到应用数据协议,所以TLS 1.3 完整握手过程只需要一个网络往返(1-RTT)。
TLS 1.3 完整握手过程图示如下:
从TLS 1.3 的握手过程可以看出;
在第一个网络往返就借助key_share 扩展字段完成了密钥协商,后续的身份认证报文均被协商出的handshake_key 加密处理,整个握手过程的明文信息减少了。为便于理解key_share 扩展字段是如何交换(EC)DHE密钥协商方案的有限域参数组(比如椭圆曲线类型)和对应的密钥协商参数的,下面给出key_share 字段的数据结构:
Halfrost-Field/TLS_1.3_Handshake_Protocol.md at master · halfrost/Halfrost-Field · GitHub struct { NamedGroup group; //有限域参数组或椭圆曲线类型 opaque key_exchange<1..2^16-1>; // 密钥协商参数 } KeyShareEntry; // 下面每一个名称对应一个确定的椭圆曲线或一组确定的有限域参数,按优先级从高到低排列,由 ClientHello报文的Extension - Supported Groups扩展字段记录这些用于密钥交换的命名组 enum { /* Elliptic Curve Groups (ECDHE) */ secp256r1(0x0017), secp384r1(0x0018), secp521r1(0x0019), x25519(0x001D), x448(0x001E), /* Finite Field Groups (DHE) */ ffdhe2048(0x0100), ffdhe3072(0x0101), ffdhe4096(0x0102), ffdhe6144(0x0103), ffdhe8192(0x0104), /* Reserved Code Points */ ffdhe_private_use(0x01FC..0x01FF), ecdhe_private_use(0xFE00..0xFEFF), (0xFFFF) } NamedGroup;
1.由于取消了密码规格变更协议,服务器在发送完CertificateVerify握手报文后可以直接发送Finished握手结束报文,服务器握手结束后在不需要对客户端进行身份认证时(也即仅对服务器端进行身份认证的情形)可以直接发送应用数据。
2.客户端完成服务器身份认证后向服务器发送自己的身份认证报文,客户端发送完Finished握手结束报文后可以直接向服务器发送应用数据(已对服务器进行过身份认证)。从客户端发送ClientHello握手报文到发送应用数据,中间只经过一次网络往返(1-RTT)。
3.TLS 1.3 完整握手过程允许服务器对客户端进行后握手身份认证(Post-Handshake Client Authentication),也即初始握手时先不对客户端进行身份认证,当客户端请求访问某些敏感资源时,才要求客户端进行身份认证。
TLS 1.3握手报文ClientHello与ServeHello在进行密钥协商时并没有进行数字签名,通信双方的身份认证主要靠后续的Certificate与CertificateVerify报文保证,因为CertificateVerify报文是对之前的握手消息(自然包括密钥协商消息)进行签名,身份认证放到后面也不会影响整个握手过程的安全性。把客户端与服务器之间完整握手过程中每个握手报文的作用及传递的主要参数字段展开,如下图所示:
TLS 1.3 完整握手过程在ClientHello与ServerHello报文中交换了各自的随机数,也协商出了预备共享密钥,使用预备共享密钥生成主共享密钥的方式跟前面介绍的TLS 1.2差不多,但升级了伪随机函数PRF。
TLS 1.3 使用HKDF(HMAC based Key Derivation Function)生成主共享密钥(TLS 1.2使用的是PRF伪随机函数),相比PRF可以输出安全性更强的新密钥。HKDF包括extract_then_expand的两阶段过程,extract过程增加密钥材料的随机性,在TLS 1.2中使用的密钥派生函数PRF实际上只实现了HKDF的expand部分,并没有经过extract,而直接假设密钥材料的随机性已经符合要求。
TLS 1.3 会话恢复 0-RTT 的简短握手
TLS 1.3 采用了新的会话缓存恢复方案 — PSK (pre_shared_key)握手,该方案相当于TLS 1.2 Session Ticket 会话恢复方案的升级版。
TLS 1.3 完整握手过程ClientHello报文中出现的两个扩展字段psk_key_exchange_modes和pre_shared_key,PSK会话缓存恢复方案正需要借助这两个字段:
TLS 1.3 完成完整握手过程后,服务器也会生成一个 New Session Ticket 并发送给客户端保存。New Session Ticket 中包含恢复共享密钥、有效期、随机数nonce等信息,可以使用New Session Ticket 中的信息生成预共享密钥PSK,过程大概如下:
struct { uint32 ticket_lifetime; uint32 ticket_age_add; opaque ticket_nonce<0..255>; opaque ticket<1..2^16-1>; Extension extensions<0..2^16-2>; } NewSessionTicket; // 通过HKDF生成预共享密钥PSK,resumption_master_secret是在完整握手过程随主密钥 一起生成的 // ticket_nonce对于每个NewSessionTicket都是不同的,保证不同的NewSessionTicket 生成不同的PSK PSK = HKDF-Expand-Label(resumption_master_secret, "resumption", ticket_nonce, Hash.length)
从上图TLS 1.3 会话恢复简短握手过程可以看出,发送首个报文ClientHello时就可以通过early_data 发送应用数据,因此从发送首个报文到发送应用数据之间并没有经过网络往返,也即0-RTT。因为发送early_data 不依赖ServerHello消息,安全性自然更弱一些,如果攻击者捕获发送到服务器的 0-RTT 数据包,他们可以重播该数据包,并且服务器可能会接受该数据包为有效数据包,甚至借此改变服务器上的重要资源状态,这就是 0-RTT 重放攻击:
为了应对 0-RTT 攻击,一般会限制 0-RTT 会话恢复的使用范围,比如在 0-RTT 中发送不改变服务器资源状态的HTTP GET报文等。TLS 1.3 会话恢复简短握手过程完成后,用于加密应用数据的密钥是双方再计算出来的密钥,包含了双方随机数或握手报文散列值信息,保证每次会话尽可能使用一次性密钥,同时也具备前向保密性。