最初的 HTTP 以明文传输方式运行在 Internet 上。随着越来越多安全敏感型应用的出现,HTTP over TCP 无法提供足够的安全性保障。SSL 及其继任者 TLS 在这样的背景下产生,提供面向信道的安全性。本文着力于展现 HTTP over TLS (即 HTTPS)的工作方式,以及与此密切相关的数字证书、对称/非对称加密等,但不涉及密码学相关实现及 SSL/TLS 的安全性证明。
概述
传输层安全性协议(Transport Layer Security, TLS) 及其先行者安全套接层(Secure Sockets Layer, SSL) 都是一种安全协议,旨在保障通信安全:
- 防窃听:避免第三方获知通信双方的通信内容
- 防篡改:避免第三方修改通信双方交换的通信内容
- 防伪造:避免第三方伪造身份参与通信
从 TCP/IP 协议栈上看,SSL/TLS 工作在应用层,作为基础性的安全协议向上服务其它应用层协议(FTP, HTTP, SSH 等)。普遍的,应用层协议使用两个不同的常用端口来区分服务是否建立在 SSL/TLS 之上。比如 HTTP 协议的 80, 443、FTP 协议的 21, 990。
SSL/TLS 运行过程
SSL/TLS 的核心是为上层协议(本文特指HTTP协议)提供安全性保障,即对信息进行加密。
加密又分两类:对称加密与非对称加密。在对称加密中,通信双方使用相同的密钥进行加解密操作,这种技术能够提供比较高的运算效率,但双方必须提前约定密钥;而非对称加密恰恰能够解决密钥约定问题,它通过通信一方 A 向另一方 B 公开提供公钥来允许 B 进行加密,由 A 使用保留的配对私钥完成解密,但这种方案带来的是运行效率的极大下降。
建立在 SSL/TLS 上的应用信息使用对称加密来完成信息交互。在能够保证密钥泄露的提前下,通信的安全性是能够得到保证的。
密钥约定
通信双方如何对密钥进行约定?在开始传递 HTTP 数据前,SSL/TLS 需要进行握手,对通信涉及到的必需信息进行协商:
- 对称加密使用的算法
- 对称加密使用的密钥
- 通信使用的压缩算法
其中对称加密算法和压缩算法的协商比较容易实现,毕竟算法实现都是公开的。难点在于如何保证在不安全的网络环境下协商密钥。
握手过程采用非对称加密来确保通信双方对密钥的协商。涉及几个阶段:
Client Hello 阶段
TCP 三次握手完成后,Client 向 Server 发起 Client Hello 消息。消息中携带随机数(Client Random)、会话ID、客户端支持的加密方案列表、客户端支持的压缩算法列表。
随机数由四字节的时间戳、28 字节的随机数共同组成。
加密方案列表的每项方案均是密钥交换算法、批量加密算法、摘要算法的组合。密钥交换使用非对称加密算法实施,提供的选项包括 RSA、Diffie-Hellman 算法(包括临时公钥的变种)。
Server Hello 阶段
Server 收到 Client 端发起的 Hello 消息后,依据客户端提供的加密、压缩可选项,回复选用的加密方案、压缩算法以及随机数(Server Random)和会话ID
- 会话ID: Server 端收到 Client 的会话ID 后,将优先从服务器的会话缓存中查找匹配项;如果发现匹配,服务器一般会恢复原有会话,此时回复的会话ID必须与 Client 发送的会话ID一致。如果没有匹配,或服务端不同意恢复会话,则响应一个不同的会话ID,或返回为空。
Server Certificate 阶段
Server Certificate 消息始终紧跟着 Server Hello 消息一起响应。一般提供 X.509 证书链,Client 借此来校验 Server 是否合法。
Server Key Exchange 阶段
一般来说,如果选择迪菲赫尔曼算法作为密钥交换算法,Server 产生一个随机数 y 和另外两个基础数 p, g,将(p, g, PubKey_A = g^y mod p) 发送给 Client。
Server Hello Done 阶段
该阶段是 Server Hello 结束的标志,不携带消息内容。
Client Key Exchange 阶段
Client 针对收到的 (p, g, PubKey_A),同样生成一个随机数 x,将 (PubKey_B = g^x mod p) 发送给 Server。
Client 和 Server 将根据各自拥有的信息 (p, g, x, PubKey_A) 和 (p, g, y, PubKey_B),计算出相同结果的 premaster-secret
$$ premaster_secret=PubKey_A^x mod p premaster_secret=pubkey_B^y mod p $$
再结合握手阶段各自交换的 Server Random 和 Client Random ,计算得到对称加密所需的密钥。
$$ master_secret = PRF(premaster_secret, “master secret”, client_random + server_random, 48) $$
X.509 证书
依赖于 SSL/TLS ,HTTPS 通信双方借助非对称加密完成密钥协商,依赖密钥实现对通信信息的加密传输。但是,Client 如何判断 Server 的身份?Server 如果想要确认 Client 的身份?这就需要依赖于证书(Certificate)了。
在开始前,罗列一下专有名词:
- PKI (Public Key Infrastructure): 公开密钥基础设施。很大程度上安全通信保障机制就是基于 PKI 建立的。
- end entity: PKI 证书的用户或用户系统
- CA (Certification Authority): 证书授权机构
- RA (Registration Authority): 证书注册机构
- CRL issuer: 生成并签名 CRL 的系统
- repository: 存储证书和 CRL 的单个系统或分布式系统,同时用于分发证书和 CRLs 到 end entities
证书是整个 PKI 的核心,是网络上的身份证明文件。在通信过程中,通过相互确认身份证明文件,才能确认自己在和对的人通信。但是,仅仅只是身份证明文件,并不能拿来做为证明。毕竟,也存在伪造的可能。这就需要权威机构来发行身份证明文件。CA 就在网络上证书发行的权威机构,像我们熟知的 “Let’s Encrypt”, “DigiCert” 等都是 CA 机构。
另一个问题,CA 机构如果在网络上证明它的身份?证书需要借助证书发行机构证明文件真伪,这形成了一条证书链,链的根证书,就是常称的 CA 证书。为避免无限递归的结果,CA 证书采用自证的方式,证书主体及签署者都是自己。而在真实世界中,由 WebTrust 机构负责对 CA 机构进行审计,而浏览器厂商只会默认认可经过 WebTrust 机构审计过的 CA 机构的证书。这也就避免了自签名证书在网络上泛滥的问题,毕竟,发行一个自签名的 CA 证书在技术上没有难度。
证书结构
一张常见的证书包含下列数据:
- 版本(Version):识别用于该证书的 X.509 标准的版本,目前有v1,v2,v3
- 序列号(Serial Number):CA 机构对其发行的证书赋予的唯一识别编号。在未来需要撤销证书时,将序列号添加到 CRL 发布到网络上。
- 证书签名算法(Signature Algorithm)
- 签署者(Issuer):发行证书的机构,一般是根 CA 证书。为这张证书做背书。
- 有效期(Validity):每个证书只能在一段有限的时期内有效。规定了起止日期。
- 主体(Subject):服务提供者在网络上的可识别名称。
- 主体公钥信息(Subject Public Key Info):提供主体的公钥,用于 SSL/TLS 认证。与证书一起被签署,被证书链信任。
- 证书签名(Signature)
下列是一张 CA 自签名证书。
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 14954122101612897031 (0xcf87b6d232746307)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=CN, ST=ZheJiang, L=HangZhou, O=ffutop.com, OU=www.ffutop.com, CN=www.ffutop.com/[email protected]
Validity
Not Before: Dec 14 00:43:06 2019 GMT
Not After : Sep 12 00:43:06 2029 GMT
Subject: C=CN, ST=ZheJiang, L=HangZhou, O=ffutop.com, OU=www.ffutop.com, CN=www.ffutop.com/[email protected]
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:a1:89:3f:fe:a5:bf:95:40:11:e6:20:21:78:81:
52:30:e9:cb:c8:bd:01:18:25:1d:0a:88:a6:8e:f5:
f2:7a:38:e3:b1:8e:96:ac:2c:d2:bd:f0:9b:6a:2c:
7a:d6:cf:71:6d:17:bf:15:cd:e8:e8:27:6a:e7:18:
48:dd:32:b7:9a:5f:2c:15:b8:69:99:6e:73:3e:9a:
cb:9f:77:fe:3e:7a:f1:c6:eb:0d:85:5c:9e:44:2d:
a1:e0:9b:30:72:14:c5:e0:4f:9e:fe:c4:3c:ce:6d:
95:c7:3d:ff:77:90:f5:c2:00:09:1e:6e:0d:28:f2:
51:bf:b3:00:d8:e7:02:50:80:76:cc:25:aa:38:14:
c3:15:b5:0b:11:34:20:92:27:8a:ac:2f:de:47:f6:
7c:f3:04:5c:e5:c1:d3:f7:88:03:92:bd:f2:47:2b:
83:c0:3c:d7:5b:6c:4a:dd:4d:ff:e3:50:9c:23:29:
75:8b:f6:fe:d9:1b:d4:c7:fc:81:70:b2:bf:5c:10:
62:64:8b:4a:d6:33:df:f7:fd:00:ea:4f:17:cb:4d:
d3:25:fb:61:68:14:0d:1d:86:b7:5f:0d:13:40:6b:
ad:27:21:bc:90:f4:eb:e6:84:c8:bf:dc:aa:89:43:
18:64:2a:b1:78:61:30:82:2d:fa:e1:82:38:f7:4b:
b8:a9
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
81:5e:de:aa:89:e6:15:97:69:ae:14:99:56:94:7d:57:4e:09:
0e:0c:b4:93:86:5a:4d:c2:e3:4e:86:ea:7e:9b:07:2e:88:16:
60:75:44:ba:4f:52:ae:e9:c1:bb:d9:13:4e:8f:47:28:7d:43:
e9:3c:40:dd:ed:d1:15:ad:e0:c4:6f:bd:f7:13:f3:b6:4c:39:
b5:f8:1e:f1:cd:b5:82:92:da:59:39:f5:0b:ce:3f:e6:a7:84:
2a:af:b6:88:9d:18:f3:0b:e3:cf:13:a7:9f:c6:18:5f:d7:66:
f5:e1:39:01:7f:06:c3:16:a2:61:aa:20:03:8f:30:15:99:a3:
c5:5c:f7:8d:d6:a9:3b:76:c0:16:e8:ac:5e:9b:40:fe:84:23:
f2:75:e7:54:2e:fb:e7:0a:c2:86:79:a9:f0:a6:db:37:ac:2d:
2e:21:53:98:3b:12:4f:91:8b:5e:5d:84:13:95:c0:f3:ef:bb:
05:e7:06:c2:99:9a:ec:eb:e2:9c:33:b9:23:fa:1d:3f:18:66:
3a:70:bd:ff:92:7a:d7:31:be:e1:45:dc:49:0c:c7:39:a7:dd:
3d:b1:a9:bc:0d:4a:48:5a:f1:40:97:3e:fe:96:fa:18:71:39:
2f:f2:6c:c4:03:82:b3:90:02:58:14:a8:4e:3a:f5:99:97:2f:
5d:2e:2d:92
参考
[1]. RFC 2246