赞
踩
HTTP 是明文传输的协议,可能受到第三方的攻击,非常不安全。因此才诞生 “HTTPS”。
这个 “S” 表示 SSL/TLS 协议,用公式说明:HTTPS = HTTP + SSL(TLS)。
其中 SSL 即安全套接层(Secure Sockets Layer),处于 OSI 七层模型中的会话层。
首先,什么是握手呢?
握手 (Handshake):指通信的前置动作,即达成某种约定,比如 TCP 握手是要确定双端的接收、发送能力等;而 TLS 握手则是为了验证身份、交换信息从而生成秘钥,为后续加密通信做准备。具体来说,SSL/TLS 握手就是通过非对称加密,生成对称加密的 session key 的过程。
通过 Wireshark 抓包发现:
不论客户端和服务端的连接走 HTTP 还是 TLS 协议,所有连接最初都要经过 TCP 三次握手,而 TLS 四次握手是在 TCP 建立连接之后进行的。
因此,HTTPS 首次通信需要 7 次握手。
本节将会解析 TLS 主要的两种握手方式,分别为:RSA 握手、DH 握手。再以 DH 握手为基础继续演进优化,推出更安全、性能更佳的 TLS1.3 版本握手方式。不过在此之前,还需要了解一些基础概念 。
加、解密使用的同一串密钥,常见的对称加密算法:DES,AES 等。
加、解密使用不同的密钥,一把作为公开的公钥,另一把作为保密的私钥。公钥加密的信息,只有私钥才能解密。反之,私钥加密的信息,只有公钥才能解密。
常见的非对称加密算法:RSA,ECC 等。
RSA 算法:该算法的命名以三位科学家的姓氏缩写组合得来,在计算机网络世界,一直是最广为使用的 “非对称加密算法”。
ECC 是非对称加密里的 “后起之秀”,它基于 “椭圆曲线离散对数” 的数学难题,使用特定的曲线方程和基点生成公钥和私钥,子算法 ECDHE 用于密钥交换,ECDSA 用于数字签名。
在 对称加密 算法中只要持有密钥就可以解密。如果你和网站约定的密钥在传递途中被黑客窃取,那他就可以在之后随意解密收发的数据,通信过程也就没有机密性可言了。
在非对称加密算法中,需要应用到复杂的数学运算,虽然保证了安全,但速度很慢,比对称加密算法差了好几个数量级。
所以,TLS 里使用了 “混合加密” 的方式博采众长:「在通信刚开始的时候使用非对称加密算法,解决密钥交换的问题。后续全都使用对称加密进行通信」。
HTTPS常用的密钥交换算法有两种,分别是RSA和ECDHE算法。
其中,RSA是比较传统的密钥交换算法,它不具备前向安全(指的是长期使用的主密钥泄漏不会导致过去的会话密钥泄漏)的性质,因此现在很少服务器使用它。而ECDHE算法具有前向安全,所以被广泛使用。
加密套件列表一般由客户端发送,供服务器选择。用 openssl 查看列表:
➜ openssl ciphers -v
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256
...
... Cipher Suites(17 suites)
上述加密套件的意思是:
证书本身是由权威、受信任的证书颁发机构 (CA) 授予的。
数字证书一般有两个作用:
整个握手过程通俗地说分为如下五步(真实的过程涉及的细节比这个多):
客户端:给出协议版本号
、一个客户端生成的随机数
(Client random),以及客户端支持的加密方法
。
服务端:确认双方使用的加密方法
,并给出数字证书
、以及一个服务器生成的随机数
(Server random)。
客户端:确认数字证书有效
,然后生成一个新的随机数
(Premaster secret),并使用数字证书中的公钥,加密这个随机数
,发给服务端。
服务端:使用自己的私钥,解密后获取客户端发的随机数
(即Premaster secret)。
客户端和服务端根据约定的加密方法,使用前面的三个随机数,生成对话密钥
(session key),用来加密接下来的整个对话过程。
客户端发送
服务端发送
ServerHello,该消息主要包含如下信息:
ServerCertificate:服务端下发SSL证书,客户端用该证书验证服务端的身份;
ServerKeyExchange【可选】:用来传递双方协商密钥的参数;
如果证书包含的信息不足以进行密钥交换,那么需要发送此种消息。一般是DHE、ECDHE相关密码套件需要发送这种子消息,因为客户端每次连接服务器都需要发送动态DH的参数和公钥等信息(证书中没有),传递这些DH的信息需要用服务器私钥(和证书中的服务器公钥是一对)进行签名。
但DH_anon、ECDH_anon(不验证身份)需要发送此子消息,因为它们没有Certificate子消息,也就是没有证书携带DH信息。
此外,RSA密码套件不需要此子消息,因为客户端可以计算预备主密钥,用服务器公钥加密,然后服务器用私钥解密即可得到预备主密钥。
DH_DSS和DH_RSA也不需要此子消息,Certificate子消息中已经包含DH信息。
ClientCertificateRequest【可选】:只有当服务端也需要验证客户端身份会用到;
ServerHelloDone:告知客户端握手相关的消息发送完毕,等待客户端响应。
客户端发送
服务端发送
ChangeCipherSpec:通知对方此消息以后会以之前协商的密钥加密发送数据;
Finished:服务器使用对称密钥加密(生成方式与客户端相同)之前所发送的所有握手消息的hash值,发送给客户端去校验。
至此 SSL 握手过程结束,双发之后的通信数据都会用双方协商的对称密钥 Session Key 加密传输。
本节使用 wireshark 抓包工具分析一个完整的 HTTPS 通信过程,看看通信过程中双方消息是如何传送的。前面我们说过,根据服务端实现的不同,可能一个 TCP 包中包含多条 SSL/TLS 消息,而不是每条消息单独发送(每条单独发送效率太低)。
下面为 Wireshark 抓取的 https 流量包,展示了整个通信过程:建立 TCP 连接 --> SSL/TLS 握手(ECDHE交换密钥) --> 应用数据加密传输:
上面是一个实际的 SSL/TLS 握手过程,分为如下 5 步:
下面我们分步分析每个阶段的包的内容:
客户端发送 Client Hello 消息给服务端
可以看出 TLS 协议分为两层:「TLS 记录层、TLS 握手层」,其中 TLS 握手层基于 TLS 记录层。
另外客户端发送的 Client Hello 消息当中包含的信息也可以看到:
服务端回应 Server Hello 消息:
Server Hello 包含如下信息:
服务端同时回应 Server Certificate、Server Key Exchange 和 Server Hello Done 消息:
可以看出每个 TLS 记录层是一个消息,服务端同时回复了有 3 个消息:Server Certificate、Server Key Exchange、Server Hello Done。
服务器通过Server Key Exchange 消息发送椭圆曲线参数,包括选定的曲线类型和曲线参数。可以看出双方密钥协商使用的是 Diffie-Hellman (迪菲) 算法,该消息用于传递 Diffie-Hellman (迪菲) 算法的参数。
客户端发送 Client Key Exchange、Change Cipher Spec 和 Client Finished 消息:
可以看出客户端同时回复了 3 个消息:Client Key Exchange、Change Cipher Spec 和 Client Finished 消息。Client Key Exchange 的内容为 Diffie-Hellman (迪菲) 算法的参数,用于生成 premaster key,然后和双方之前的随机数结合生成对称密钥。
服务端最后发送 Change Cipher Spec 和 Server Finished 消息:
服务端最后发送 Change Cipher Spec 和 Server Finished 消息,至此 SSL/TLS 握手完毕,接下来双方会用对称加密的方式加密传输数据。
client_random
,server_random
和主密钥
一起确定。下面这张图展示了ServerKeyExchange消息的参数,其中Pubkey是服务器计算出来的公钥(私钥不可见),再加上自己的私钥签名认证(签名算法为RSA):
下面这张图展示了ClientKeyExchange消息的参数,同样地,Pubkey是客户端计算出来的公钥(私钥不可见)。
计算预主密钥和主密钥的详细过程:
客户端首先根据服务器的公钥
及自身的私钥
计算出预主密钥Pre-master key
,然后再使用 Client Random、Server Random、Pre-master key
这三个随机数计算出主密钥 Master Secret
,保存在本地。并使用 Change Cipher Spec 消息将通知服务器开始使用对称加密的方式进行通信。
服务器也是使用同样的方式计算出预主密钥和主密钥。
总结:
客户端向服务端发送随机数 client_random,TLS 版本和供筛选的加密套件列表。
// RSA
服务端接收到,立即返回 server_random,确认好双方都支持的加密套件,以及服务端证书 (证书中附带公钥)。
// DH
服务端接收到,立即返回 server_random,确认好双方都支持的加密套件,以及服务端证书 (证书中附带公钥)。
同时服务端利用私钥将 client_random、server_random、server_params(DH算法参数) 签名,生成服务端签名。然后将签名和 server_params 也发送给客户端。
// RSA
客户端接收,先验证服务端证书。
若通过,接着使用加密套件的密钥协商算法 ——RSA 算法,生成另一个随机数 premaster secret(预主密钥),并且用证书里的公钥加密,传给服务器。
// DH
客户端接收,先验证服务端证书和签名。
若通过,客户端生成自己私钥,然后根据服务器公开的DH算法参数,算出公钥,发送给服务端。
// RSA
服务端用私钥解密这个被加密后的 premaster secret。
// DH
现在客户端和服务器都有 client_params、server_params 两个参数(双方的公钥),通过对方的公钥,自己的私钥,DH算法的公共参数都已经得到,即可算出预主密钥。最终的主密钥,通过client_random,server_random和预主密钥一起确定。
主密钥和其他参数共同计算出会话密钥,作为后续通信的对称密钥。
更快的访问速度
使用 TLS 1.2 需要两次往返( 2-RTT )才能完成握手,然后才能发送请求。
TLS 1.3 的握手不再支持静态的 RSA 密钥交换,这意味着必须使用带有前向安全的 Diffie-Hellman 进行握手。
使用 TLS 1.3 协议只需要一次往返( 1-RTT )就可以完成握手。如下图所示:
更强的安全性
TLS 1.3 在之前版本的基础上删除了那些不安全的加密算法,包括:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。