1、前言
HTTP 协议设计目的很简单:就是为了传输超文本文件,那时候也没有很强的加密传输的数据需求。因此 HTTP 一直都是明文传输的。与此同时,HTTP 在「身份验证」和「完整性校验」这两点上也是比较欠缺的。
SSL(全称为 Secure Sockets Layer,安全套接层) 是 Netscape 公司在 90 年代开发设计出来的一套东西,主要是为了解决 HTTP 协议明文传输数据的问题。后来 SSL 慢慢成了事实上的标准,于是 IETF 就把 SSL 标准化了,名字叫做 TLS(全称 Transport Layer Security,传输层安全协议),TLS 1.0 其实就是 SSL 3.1。所以 SSL 和 TLS 经常被放在一起写成 SSL/TLS,因为这两个名词其实是同一个东西的在不同阶段的名称。
HTTPS 并非是应用层的一种新协议,只是 HTTP 通讯接口部分用 SSL/TLS 协议代替,通常 HTTP 直接和 TCP 通信,当使用 TLS 时,则演变成先和 TLS 通信,再由 SSL 和 TCP 通信,也就是说 HTTPS 其实是身披 TLS 保护外衣的 HTTP。
有 HTTP 基础的同学,只要理解 SSL/TLS 也就理解了 HTTPS。
结合上面所述 HTTP 的缺点,SSL/TLS 需要解决三大问题
- 窃听风险(eavesdropping):第三方可以获知通信内容。
- 篡改风险(tampering):第三方可以修改通信内容。
- 冒充风险(pretending):第三方可以冒充他人身份参与通信。
其中,窃听风险可以通过加密来解决,篡改风险可以通过数字签名验证解决,冒充风险可以通过 CA 颁发的数字证书来解决。下面会依次介绍这几个概念。
2、前置知识
2.1、加密算法简介
可逆的加密算法通常分为两大类,对称加密和非对称加密。
- 对称加密中,加密和解密使用的是同一个密钥。
- 常见的对称加密算法有 DES、AES、RC
- 优点:相对于非对称加密算法来说,加解密的效率更高。
- 缺点:密钥管理和分发不是非常安全。在网络上传输加密文件时,如果采用对称式的加密算法就很难不把密钥告诉对方,而要把密钥告诉对方,就很可能被别窃听到。
- 非对称加密中,加密和解密使用不同的密钥。分为公钥和私钥。公钥是对外公布的,私钥仅有持有人自己知道。使用公钥对数据进行加密,只能通过私钥进行解密。使用私钥对数据进行加密,只能通过公钥进行解密。
- 常见的非对称加密算法有 RSA、ECC。
- 优点:加密安全性高,公钥可以 避免密钥传输的安全性问题,
- 缺点:加密效率低。
2.2、消息摘要,数字签名,数字证书
消息摘要 :对一段任意长度消息使用 hash 算法得到 固定长度的一个字符串
数字签名:加密过后的消息摘要。这里的加密使用的是非对称加密。
- 作用:
- 身份验证,能确定消息确实由发送方签名然后发出来的,因为加密需要用到发送方的私钥,这个私有只有发送方才有,因此别人假冒不了发送方的签名。
- 消息的完整性验证。
- 使用流程
- 发送方
- 对消息进行 hash,得到消息摘要
- 使用私钥对消息摘要进行加密得到数字签名
- 即
明文——>hash运算——>(固定长度的)摘要——>私钥加密——>数字签名
- 接收方
- 使用公钥对数字签名进行解密得到消息摘要 A
- 对收到的消息进行 hash 得到「消息摘要 B」,与消息摘要 B 进行,如果 A 与 B 一致,那说明没有被篡改。
- 发送方
- 你可能会问:
- 消息摘要为啥需要加密呢?不加密不行吗?
- 如果不对消息摘要进行加密,那么中间人/第三方 只需要同时修改 消息内容和 消息摘要,就能让接收方 验证通过,对篡改过的信息 信以为真。
- 其实关键是加密的时候,使用的是发送方的私钥,私钥只有发送方才有,因此如果 使用公钥解密之后,可以验证通过,就能够说明内容是发送方发出的。
- 发送方直接使用私钥对要发送的消息进行加密不行吗?
- 接收方解密可以得到消息,但是存在被第三方恶意截断的可能性,无法保证完整性。
- 比如,发送方发送了 「今天天气晴朗也不太热,我们去爬山吧」,可能被截断为「今天天气晴朗也不太热」
- 消息摘要为啥需要加密呢?不加密不行吗?
- 作用:
数字证书:采用 HTTPS 协议的服务器必须要有一套数字证书,可以是自己制作或者是找 CA 申请颁发证书。CA(证书中心)用自己的私钥,对相应网站的公钥和一些相关的信息一起加密,生成「数字证书」。
对于请求方来说,它怎么能确定它所得到的公钥一定是从目标主机那里发送的,而且没有被篡改过呢? 亦或者请求的目标主机本身就是从事窃取用户信息的不正当行为呢?
这时候,我们需要一个权威的值得信赖的第三方机构 (一般是由政府机构审核并授权的机构) 来统一对外发送主机机构的公钥,只要请求方从这种机构获取公钥,就避免了上述问题
作用:身份验证,保证拿到的公钥确实是某个网站的,而不是伪造的。各大 CA 机构的公钥是默认安装在操作系统里的,所以不要安装来路不明的操作系统,否则相当于裸奔。
客户端是否能够信任这个站点的证书,首先取决于客户端程序是否导入了证书颁发者的根证书。如果是自己制作的证书需要客户端手动验证通过,才可以继续访问,而使用 CA 证书则不会弹出提示页面。
3、TLS1.2 握手流程
前面提到,非对称加密在性能上不如对称加密,但是非对称加密的没有密钥分发上的问题,是否可以将两者结合起来呢?比如说,非对称加密用来传输对称加密密钥的参数,后续真正通信都通过对称加密来进行。
SSL/TLS 握手是为了安全地协商出一份对称加密的秘钥,这个过程很有意思,下面我们一起来了解一下。
借用 CloudFlare 的一个图(省略了部分细节,但是整体流程大致如下)

借助 Wireshark 抓包直观还原握手流程:
- 打开 WireShark,启动抓包
- 然后在命令行中执行
curl https://www.baidu.com - 选中某一行,右键「追踪流」—> 「TCP 流」
得到下图👇
流程说明:
1、通过 TCP 三次握手建立连接
2、Client Hello
由于客户端 (如浏览器) 对一些加解密算法的支持程度不一样,但是在 TLS 协议传输过程中必须使用同一套加解密算法才能保证数据能够正常的加解密。因此在 TLS 握手阶段,客户端要首先告知服务器,自己支持哪些加密算法,所以客户端需要将本地支持的加密套件 (Cipher Suite) 的列表传送给服务器。除此之外,客户端还要产生一个随机数,这个随机数一方面需要在客户端保存,另一方面需要传给服务器,客户端的随机数后面会跟服务器的随机数、以及 pre-master 结合起来生成对称加密的密钥。
客户端需要提供如下信息:
1、支持的协议版本,比如 TLS 1.2 版本 2、一个客户端生成的随机数(我们称之为 A),稍后用于生成 “对话密钥”3、支持的加密算法,比如 RSA 公钥加密 4、支持的压缩方法
PS:客户端发送的信息之中不包括服务器的域名,也就是说,理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的提供的数字证书。这就是为什么通常一台服务器只能由一张数字证书的原因
对于虚拟主机的用户来说,这当然很不方便。2006 年,TLS 协议加入了 Server Name Indication 扩展,允许客户端向服务器提供它所请求的域名。然后客户端
3、Server Hello
服务端发送给客户端
- 确定加密通信协议的版本,比如 TLS1.2。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信
- 结合客户端发过来的 Cipher Suite 确定使用的加密算法。
- 比如
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,就是使用 ECDHE 做密钥交换, AES-128 的 GCM 模式进行对称加密,同时以带 SHA-256 的 RSA 作为签名算法。 - 使用 curl 命令 结合 WireShark 抓包查看 zhihu,com,baidu.com 发现这两个网站都是使用
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256算法,也就是使用 AES-128 的 GCM 模式进行对称加密,同时以带 SHA-256 的 RSA 作为签名算法,用 ECDHE 做密钥交换的一整套协议。
- 比如
4、Certificate
服务端发送给客户端(如果是双向验证的话,客户端也需要发送证书给服务端),接收方会进行证书验证,如果不通过的话,会中断握手流程。
5、Server Key Exchange
服务端发送给客户端。加密密钥的参数
- 假设使用的是 ECDHE,这里传输的内容有:椭圆曲线域参数,以及公钥的值。
6、 Server Hello Done
- 服务器发送的,一般也和 Server Hello、Certificate 和 Server Key Exchange 在一个 TCP 报文中,介于 Server Hello 和 Server Hello 之间的是服务器想要给客户端的东西。所以这里面客户端没有发送 Client Hello Done
通常,3~6 这个四个步骤会在一个 TCP 报文中。
也就是说,服务端的一个 TCP 报文中,可能会包括
- 协议的版本,比如 TLS1.2 版本,如果浏览器与服务器支持的版本不一致,服务器关闭加密通信
- 加密的算法
- 随机数
- 服务器证书
除了上面这些信息,如果服务器需要确认客户端身份,就会再包含一项请求,要求客户端提供「客户端证书」。比如,金融机构往往只允许认证客户进入自己的网络,就会向正式客户提供 USB 密钥,里面包含了一张客户端证书。(以前经常用到的 U 盾。U 盾又叫作移动数字证书,它存放着你个人的数字证书,并不可读取。同样,银行也记录着你的数字证书)。
7、 Client Key Exchange
客户端收到了服务器的证书之后进行验证,如果验证通过了,会继续密钥协商的流程。
- 客户端发送给服务端,一个随机数(称为 pre-master),使用服务端证书中的公钥对 pre-master 进行加密,然后发送给服务端。这一步之后,客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把”会话密钥”。
如果证书不是可信任机构颁布、或者证书中的域名和实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。
PS:验证证书主要根据服务端发过来的证书名称,在本地寻找其低级证书,并一级一级直到根证书,验证各级证书的合法性。
8、 Change Cipher Spec
- 客户端或者服务器发送的,紧跟着 Key Exchange 发送,代表自己生成了新的密钥,通知对方随后将更换密钥,信息都将用双方商定的加密算法和密钥发送
9、 Encrypted Handshake Message
- 客户端或者服务器发送的,也是紧跟着 Key Exchange 发送。这里是进行一下测试,一方用自己的刚刚生成的密钥加密一段固定的消息发送给对方,如果密钥协商正确无误的话,对方应该可以解密。这段加密内容的明文一般是协议中规定好的,双方都知道。
10. New Session Ticket
- 服务器发送的,属于 TLS handshake,服务器给客户端一个会话,用处就是在一段时间之内(超时时间到来之前),双方都以刚刚交换的密钥进行通信。从这以后,加密通信正式开始。
11. Application Data
- 应用层的数据,是加密的,使用密钥交换协议协商出来的密钥加密。因为我们的 Wireshark 不知道服务器的私钥,所以这段通信是安全的,我们在 Wireshark 中也无法解密这段信息。
12. Encrypted Alert
- 客户端或服务器发送的,意味着加密通信因为某些原因需要中断,警告对方不要再发送敏感的数据。
4、TLS1.3
1、TLS1.2 存在的问题
整个握手流程需要 2-RTT,这在网络延迟较高的情况下是非常糟糕的,可能导致握手延迟增加几百毫秒。更糟糕的是,握手阶段的数据(如 ServerHello 阶段的信息),并不是加密的,中间人稍加利用,从中选择比较弱的加密算法,就可以带来降级攻击(Downgrade Attack)。

2、TLS 1.3发展时间线
- 2017年4月25日,nginx 1.13.0 发布,增加了 TLS 1.3 支持。
- 2018年3月21日,IESG 批准了 TLS 1.3 草案。
- 2018年4月17日,Chrome 66 默认开启了对 TLS 1.3 草案的支持。
- 2018年5月9日,Firefox 60 默认开启了对 TLS 1.3 草案的支持。
- 2018年8月10日,IETF 发布了 TLS 1.3 标准。
- 2018年9月11日,OpenSSL 1.1.1 (LTS) 版本发布,提供 TLS 1.3 支持。TLS 1.3 超过 TLS 1.0 成为 Cloudflare 上使用率排名第二的 TLS 版本。
- 2018年10月16日,Chrome 70 支持 TLS 1.3 正式标准。
- 2018年10月23日,Firefox 63 支持 TLS 1.3 正式标准。
3、TLS1.3 的优点
更安全
TLS 1.3 在之前版本的基础上删除了那些不安全的加密算法,这些加密算法包括:
- RSA 密钥传输 —— 不支持前向安全性
- CBC 模式密码 —— 易受 BEAST 和 Lucky 13 攻击
- RC4 流密码 —— 在 HTTPS 中使用并不安全
- SHA-1 哈希函数 —— 建议以 SHA-2 取而代之
- 任意 Diffie-Hellman 组—— CVE-2016-0701 漏洞
- 输出密码 —— 易受 FREAK 和 LogJam 攻击
更快
虽然电脑越变越快,但在互联网上传输数据耗费的时间依然受限于光速,所以两个节点间来回传输一次的时间(RTT)成为了限制协议性能的因素之一。TLS 1.3 只需要一个 RTT 就能完成握手,相比 TLS 1.2 省去了一个 RTT。并且 TLS 1.3 支持 「0-RTT」 模式,在该模式下客户端可以在握手的同时发送数据,极大地加快了页面的加载速度。TLS 1.3 还增加了 ChaCha20/Poly1305 支持,在不支持 AES 硬件指令的老设备上能提升加、解密性能。
|
|
TLS 1.2 完整握手框架(来自 RFC 5246)👆
使用 TLS 1.2 需要两次往返( 2-RTT )才能完成握手,然后才能发送请求。
|
|
TLS 1.3 完整握手框架(来自 TLS 1.3 最新草案 )👆
TLS 1.3 的握手不再支持静态的 RSA 密钥交换,这意味着必须使用带有前向安全的 Diffie-Hellman 进行全面握手。从上图可以看出,使用 TLS 1.3 协议只需要一次往返( 1-RTT )就可以完成握手。
5、总结
HTTPS 通过 TLS 实现安全。TLS 在握手阶段完成了加密算法的选择以及加密密钥确认,同时对服务端进行了身份认证。握手完成后的通信会通过这个阶段商讨出的对称密钥进行加解密。
由于需要比 HTTP 多一个 TLS 握手🤝协商密钥的流程,所以 HTTPS 比 HTTP 慢。
附:HTTPS 能够防止抓包吗?
HTTPS 可以防止用户在不知情的情况下通信链路被监听,但是对于主动授信的抓包操作是不提供防护的,因为这个场景用户是已经对风险知情。
一般来说默认信任的根证书都是系统/浏览器预装的。我们国内有不少盗版的 Windows 操作系统,这些系统内部可能预装了一些第三方的证书,这种情况下,就算用 HTTPS 通信,也有很高的泄漏风险。
6、参考资料与学习资源推荐
由于本人水平有限,可能出于误解或者笔误难免出错,如果发现有问题或者对文中内容存在疑问欢迎在下面评论区告诉我,请对问题描述尽量详细,以帮助我可以快速找到问题根源。谢谢!
- TLS 握手过程
- https://tools.ietf.org/html/rfc8446
- https://www.giuem.com/tls-1-3-overview/
- https://www.jianshu.com/p/efe44d4a7501
- http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
- https://segmentfault.com/a/1190000014740303
- http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html?from=singlemessage
- https://zhuanlan.zhihu.com/p/32754315
- https://juejin.im/post/5c21f5b16fb9a049d13229f0
- HTTPS 温故知新(三) —— 直观感受 TLS 握手流程(上)