HTTPS
# HTTP 存在的问题
内容是明文传输的,没有经过任何加密,而这些明文数据会经过 WiFi、路由器、运营商、机房等多个物理设备节点,如果在这中间任意一个节点被监听,传输的内容就会完全暴露,这一攻击手法叫做 MITM(Man In The Middle)中间人攻击。
为了解决 HTTP 明文传输数据可能导致的安全问题,1994 年网景公司提出了 HTTPS(HyperText Transfer Protocol Secure)超文本传输安全协议,数据通信仍然是 HTTP,但利用 SSL/TLS 加密数据包。
# HTTPS
超文本传输安全协议:是一种通过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。主要作用是在不安全的网络上创建一个安全信道,并可在使用适当的加密包和服务器证书可被验证且可被信任时,对
窃听
和中间人攻击
提供合理的防护。
HTTPS 的信任基于预先安装在操作系统中的证书颁发机构(CA)。HTTP 的 URL 是由http://
起始与默认使用端口 80,而 HTTPS 的 URL 则是由https://
起始与默认使用端口 443。
# TLS 握手过程
# RSA 握手过程
# 大体流程
- 浏览器发送自己支持的
TLS版本
+加密套件列表
+client-random
发送到服务端 - 服务端发送
选定的TLS版本
+选定的加密套件
+service-random
+包含服务端公钥的证书
发送到客户端 - 客户端收到响应之后,先验证数字证书。若通过,此时客户端利用
RSA
算法将client-random
+service-random
这两个随机数生成pre-master
,并通过服务端公钥加密后传递个服务端 - 服务端通过私钥解密出
pre-master
,并返回给客户端确认信息 - 到此,服务器和浏览器就有了共同的
client-random
、service-random
和pre-master
,然后服务器和浏览器会使用这三组随机数通过相同的伪随机函数(服务器与客户端约定的加密套件),生成用于后续数据传输加密的对称密钥 master secret
,因为服务器和浏览器使用同一套方法来生成密钥,所以最终生成的密钥也是相同的 - 有了对称加密的密钥之后,双方就可以使用对称加密的方式来传输数据了
# 数字证书的验证
上面提到了中间人攻击的场景,服务端向客户端发送公钥的过程,这个公钥是有可能被黑客拿到并伪造成服务端和客户端拦截双方通信,并解密传输的消息的。所以要解决这个问题,就需要保证服务端发送过来的公钥的确是由真正的可信任的服务器发送过来的。这个时候就需要用到数字证书。
证书颁发流程
- 服务器的运营人员会向认证机构提交自己的公钥、组织信息、个人信息等并申请认证,认证机构会通过线上线下的方式验证申请者提交信息的真实性
- 验证通过后,认证机构给这些信息(申请者的公钥,组织信息,个人信息以及认证机构自己的信息等),我们简称为明文信息,进行数字签名:
- 通过 Hash 函数为证书的明文信息生成一个信息摘要
- 认证机构使用自己的私钥对摘要信息进行加密处理
- 之后会将明文信息和数字签名组合而成的证书颁发给申请者,也就是服务器
浏览器验证流程
- 首先就是要验证域名、有效期等明文信息是否正确
- 客户端采用相同的 Hash 函数 为明文信息生成一个 信息摘要 A,
- 然后再用内置在浏览器上的 CA 的公钥(CA 机构的公钥又不是随便人能拿到的,只有各大浏览器厂商才有)来解密证书里的数字签名,得到一个信息摘要 B
- 最后将两个信息摘要 A 和 B 进行对比,若是一样则能保证通信方的身份是正确的
这时候相当于验证了 CA 是谁,但是这个 CA 可能比较小众,浏览器不知道该不该信任它,然后浏览器会继续查找给这个 CA 颁发证书的 CA,再以同样的方式验证它上级 CA 的可靠性。 通常情况下,操作系统中会内置信任的顶级 CA 的证书信息(包含公钥),如果这个 CA 链中没有找到浏览器内置的顶级的 CA,证书也会被判定非法
# DCDHE 握手过程
# 大体流程
- 浏览器向服务器发送随机数
client_random
,TLS 版本和供筛选的加密套件列表。 - 服务器接收到,然后将
server_random
、确认好双方都支持的加密套件、数字证书 (证书中附带公钥) 和server_params
发送给客户端 - 浏览器接收之后做两件事:
- 先验证数字证书和签名。若通过,发送
client-param
到服务端 - 使用
ECDHE 算法(client-param, server-param) = pre-random
得到pre-random
,然后通过client-random
+server-random
+pre-random
通过 伪随机数函数(服务器与客户端约定的加密套件) 生成最终的 secret,这个就是后续对称加密要使用的密钥
- 先验证数字证书和签名。若通过,发送
- 服务器它在接收到刚刚传递过来的 client_params 之后,也会使用和客户端一样的方式生成 secret,并且也会发送一个收尾消息给客户端。
- 当双方都收到收尾消息并验证成功之后,握手就结束了。后面开始用这个 secret 对称密钥加密报文进行传输。
ECDHE 非对称密钥的加密算法彻底取代了 RSA 加密算法。原因是:RSA 被发现了漏洞,一旦服务器私钥被获取,之前所有的对称密钥都会获取,所有被加密的报文都会被破译。而 ECDHE 算法在每一次握手时,生成的是不同的 pre_random,进而每一次握手的对称密钥也不同,即使私钥被破解,也不影响历史消息。这种一次破译不影响历史信息的性质也叫前向安全性。 RSA 不具备前向安全性,而 ECDHE 具备,所有在 TLS 1.3 中 RSA 被彻底取代。
# TLS1.3 握手
强化安全
在 TLS1.3 中废除了非常多的加密算法,只保留五个加密套件
提升性能
- 握手改进
大体的方式和 TLS1.2 差不多,不过和 TLS 1.2 相比少了一个 RTT, 服务端不必等待对方验证证书之后才拿到 client_params,而是直接在第一次握手的时候就能够拿到, 拿到之后立即计算 secret,节省了之前不必要的等待时间。同时,这也意味着在第一次握手的时候客户端需要传送更多的信息,一口气给传完。
这种 TLS 1.3 握手方式也被叫做 1-RTT 握手
- 会话复用
会话复用有两种方式: Session ID 和 Session Ticket。
先说说最早出现的 Seesion ID,具体做法是客户端和服务器首次连接后各自保存会话的 ID,并存储会话密钥,当再次连接时,客户端发送 ID 过来,服务器查找这个 ID 是否存在,如果找到了就直接复用之前的会话状态,会话密钥不用重新生成,直接用原来的那份。
但这种方式也存在一个弊端,就是当客户端数量庞大的时候,对服务端的存储压力非常大。
因而出现了第二种方式——Session Ticket。它的思路就是: 服务端的压力大,那就把压力分摊给客户端呗。具体来说,双方连接成功后,服务器加密会话信息,用 Session Ticket 消息发给客户端,让客户端保存下来。下次重连的时候,就把这个 Ticket 进行解密,验证它过没过期,如果没过期那就直接恢复之前的会话状态。
这种方式虽然减小了服务端的存储压力,但与带来了安全问题,即每次用一个固定的密钥来解密 Ticket 数据,一旦黑客拿到这个密钥,之前所有的历史记录也被破解了。因此为了尽量避免这样的问题,密钥需要定期进行更换。