理解 HTTPS

简介

HTTPS 中的 S 代表 Secure,所以 HTTPS 自然就是更安全的 HTTP 的意思。互联网诞生之初 SSL(Secure Sockets Layer 安全套接层)是由 Netscape 这家最早的浏览器公司设计的,主要是用于 Web 的安全传输的协议,这种协议在早期 Web 上获得了广泛的应用。后来被 IETF 标准化形成了 TLS(Transport Layer Security 传输层安全)标准,其历史如下:

  • 1994: SSL1.0,因为存在严重的安全漏洞,未发布。
  • 1995: SSL2.0,这个版本由于设计缺陷,很快被发现有严重漏洞,被废弃。
  • 1996: SSL3.0,重新设计并开始流行,SSL 前三个版本都是由 Netscape 设计实现,有已知漏洞,建议弃用。
  • 1999: TLS1.0,IETF 将 SSL 标准化,即 RFC 2246,也存在部分安全漏洞,比如 RC4 和 BEAST 攻击。
  • 2006: TLS1.1,作为 RFC 4346 发布。
  • 2008: TLS1.2,作为 RFC 5246 发布 。
  • 2015: TLS1.3,尚在制定中,处于草案阶段。

如上,现在互联网世界使用最广泛的应该是 TLS1.2 标准。

##目标

SSL/TLS 最初的设计目标就是为了实现下面三个目的:

  1. 保密:第三方无法窃听。
  2. 完整:无法篡改。
  3. 认证:防止身份冒充。

结构

整个互联网构建于 TCP/IP 协议栈基础之上,SSL/TLS 协议处于该分层协议栈结构中的会话层位置:

流程和步骤

1. 客户端发起 HTTPS 请求

客户端向服务端传送:

  • SSL Version : 自己支持的最高协议版本,比如 TLS 1.2
  • Ciphers : 支持的加密套件,比如: RSA 非对称加密算法,AES 对称加密算法
  • 随机数 (A) RandomC

2. 服务端的配置

服务器的数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面。

这套证书其实就是一对公钥和私钥。可以想象成一把钥匙和一个锁头,全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。

关于数字证书可以查看另一篇:数字签名是什么?

3. 传送证书

服务端向客户端传送证书,包含以下信息:

  • 服务器公钥(明文)
  • 申请者的组织信息和个人信息
  • 签发机构 CA 的信息
  • 有效时间、证书序列号等信息(明文)
  • 发行者的数字签名:使用散列函数计算公开的明文信息的摘要,然后用 CA 的私钥对信息摘要进行加密,密文即签名

同时会一并做传送以下信息:

  • 确认使用的 SSL 协议的版本号
  • 加密套件 Cipher Suite
  • 随机数 (B) RandomS
  • CertificateRequest 可选,Server 端需要认证 Client 端身份的请求时发送。 比如,银行提供的各类 U 盾,其实就是一种 Client 证书,一般在线使用专业版网银时才需要。
  • ServerHelloDone 表示 Server 响应结束。

4. 客户端验证证书

客户端的 TLS 来验证证书的合法性:

  • 证书是否过期
  • 签发机构 CA 是否可靠
  • 签发机构 CA 的公钥来验证服务器证书的发行者数字签名
  • 证书上的域名和服务器的实际域名是否一致

如果证书没有问题,那么就生成一个随机数 (C)。然后把三个随机数 A+B+C 拼接成一个新的随机数 (D),用服务端公钥(证书里解析得来)对随机数 (D) 进行加密,形成行动暗号

如果发现异常,浏览器则会弹出一个警告框,提示证书存在问题。如果这时用户仍然选择『继续』,就表示不验证证书合法性,直接把证书里的 服务端公钥拿来用就是了。

5. 传送暗号

客户端把行动暗号发送给服务端,以后两边的通信就通过这个暗号来进行对称加、解密了。

同时向服务端传送以下信息:

  • Certificate 如果在ServerHello 时服务端要求客户端 U 盾验证,那么 Client 端也会在这一步响应 Server 的 CertificateRequest 请求。
  • CertificateVerify 用于对客户端 U 盾证书提供证明,对于特定的证书需要可选发送。
  • ChangeCipherSpec 告知 Server,Client 已经切换到之前协商好的加密套件(Cipher Suite)的状态,准备加密数据并传输了。
  • ClientFinished Client 会用协商好的算法先加密一小段 Finished 的数据传送给 Server,为了在正式传输前做最后验证。

6. 服务端获取暗号

服务端用自己的私钥解密得到了客户端传过来的行动暗号。同时服务端回应以下信息:

  • NewSessionTicket 表示新建了一个会话票据,传递给 Client。若连接意外中断 Client 需要重建会话时,可以复用该票据,加速握手过程。
  • ChangeCipherSpec 告知 Client,Server 已经切换到协商过的加密套件状态,准备加密数据并传输了。
  • ServerFinished Server 会用协商好的算法加密一小段 Finished 的数据传送给 Client,为了在正式传输前做最后验证。

至此,整个 SSL 握手阶段全部结束。接下来 Client 和 Server 进入使用会话密钥的加密通信过程。

7. 服务端返回加密信息

服务端用行动暗号把数据加密后发回给客户端。

8. 客户端解密信息

客户端用行动暗号解密服务端发过来的信息。

完成!

FAQ

Q: 应用层数据为什么不用非对称加解密?性能开销太大,无法承受。

A: CPU 计算资源消耗非常大。一次完全 TLS 握手,密钥交换时的非对称解密计算量占整个握手过程的 90% 以上。而对称加密的计算量只相当于非对称加密的 0.1%。 非对称加密算法对加密内容的长度有限制,不能超过公钥长度。比如现在常用的公钥长度是 2048 位,意味着待加密内容不能超过 256 个字节。

所以公钥加密目前只能用来作密钥交换或者内容签名,不适合用来做应用层传输内容的加解密。

Q: 交互过程中到底有几个随机数?

A: 一共有三个随机数。

  • 第1个 RandomC 由 clientHello 时生成发送给服务端
  • 第2个 RandomS 由 serverHello 时生成发送给客户端(随着 CA 证书一起发回)
  • 第3个 PreMaster 由客户端生成

根据三个随机数,计算得到行动暗号

PreMasterSecret = crypt(RandomC, RandomS, PreMaster)

至于为什么要用三个随机数,是为了增加更多随机因素,防止被猜出。

参考文章: