很多市面上的书籍对HTTPS基于的TLS协议介绍还停留在1.2的版本上,然而新的TLS1.3已经对1.2进行了很大的改进,优化了握手过程,访问速度更快;删除了(不采用)一些不安全的加密算法,安全性更强。因此,有必要结合TLS1.2来了解下基于TLS1.3的HTTPS协议。
TLS 1.2握手过程
TLS 1.3握手过程
TLS1.2里交互过程需要2-RTT,而TLS1.3只需要1-RTT,流程如下:
【第1步】客户端发送 ClientHello
消息,该消息主要包括客户端支持的协议版本、会话ID、密码套件、压缩算法、以及扩展消息(密钥共享、预共享密钥、预共享密钥模式);【第2步】服务端回复
ServerHello,包含选定的加密套件;发送证书给客户端;使用证书对应的私钥对握手消息签名,将结果发送给客户端;选用客户端提供的参数生成临时公钥,结合选定的参数计算出用于加密HTTP 消息的共享密钥;服务端生成的临时公钥通过 KeyShare 消息发送给客户端;【第3步】客户端接收到 KeyShare 消息后,使用证书公钥进行签名验证,获取服务器端的临时公钥,生成会话所需要的共享密钥;
【第4步】双方使用生成的共享密钥对消息加密传输,保证消息安全。
TLS1.2比TLS1.3在握手过程中多了一次握手,为什么会多这一次握手?
握手是为了协商出一个client和server端都认可的一个对称密钥,典型的密钥协商算法有两种,RSA和ECDH,那么TLS1.2采取的是RSA,TLS1.3采取的是ECDH。
对于RSA的密钥协商过程,RSA有一个很棒的特性:RSA算法给予服务端一对公钥和私钥,一段消息既可以用公钥加密,然后用私钥解密,也可以用私钥加密,用公钥解密。不难理解,私钥只在服务端保存用来解密或签名,而公钥给客户端用来加密或验证签名。TLS1.2的密钥协商过程,首先client发一个client_hello,然后server端收到这个消息后,回传一个server_hello,一个证书,client收到证书后,用公钥(证书中提供)加密一段随机数发回给server,server收到后用私钥解密得到这段随机数,这段随机数就作为对称加密的密钥了,至此握手完成。
再来看下ECDH的秘钥协商过程,首先EC的意思是椭圆曲线,这个EC提供了一个很厉害的性质,你在曲线上找一个点P,给定一个整数K,求解Q=KP很容易,给定一个点P,Q,知道Q =KP,求K却是个难题。在这个背景下,给定一个大家都知道的大数G,client在每次需要和server协商密钥时,生成一段随机数a,然后发送A=a * G给server,server收到这段消息(a * G)后,生成一段随机数b,然后发送B=b * G给client,然后server端计算(a * G) * b作为对称密钥,client端收到b * G后计算a * (G * b),因为(a * G) * b = a * (G * b),所以对称密 钥就是a * G * b啦,攻击者只能截获A=a * G和B=b * G,由于椭圆曲线难题,知道A和G是很难计算a和b的,也就无法计算a * G * b了(当然,实际上的计算过中间还有一个取模的过程,以及取模过程的交换律和结合律证明,但本质思想和这个是差不多的)。client发送client_hello,server收到后发送server_hello和ECC证书(B =b * G),client收到后就生成随机数a,然后发送a * G给server,并记录密钥,server收到a * G后计算对称密钥,握手就结束了。 TLS1.3图中的key_share,这段的功能就是直接记录了a * G,然后包含在client_hello中。然后server收到后在server_hello的key_share段中记录b * G。所以TLS1.3一个RTT就搞定握手了。
抓包分析
客户端请求(Client Hello)
可看到客户端支持的TLS版本为v1.2,生成的随机数,支持的加密套件有16种,此外还有支持的压缩方法以及一些扩展字段信息。
支持的密码套件中属于TLS1.3的有:
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
key_share 是椭圆曲线类型对应的公钥,signature_algorithms是客户端提供签名算法,psk_key_exchange_modes是psk密钥交互模式选择
服务端响应(Server Hello)
服务端选择的加密套件是TLS-AES256-GCM-SHA384,注意TLS 1.3 的握手不再支持静态的 RSA 密钥交换,这意味着可以使用带有前向安全的 Diffie-Hellman 进行全面握手,密钥交换机制可提供前向保密。
同时还包含服务端的keyshare,可以理解为b * G。以及Change Cipher Spec协议让客户端重新计算共享密钥。还可看到服务端此时已经可以发送应用数据,因为服务端根据a * G,计算出了 a * G * b(共享密钥),于是用这个共享密钥加密数据并发送。
客户端认证,传输数据
客户端认证完成,发送给服务端,至此建立连接,客户端也可以发送数据。