https 的实现涉及了众多密码学算法的应用, 为了保证信息传输的绝对安全衍生出了众多概念, 环环相扣, 逻辑无比严密, 值得详细地梳理与记录;
密码学基础知识
对称加密
定义一个密钥 secretKey
, 用其对明文进行加密, 同理用这把密钥也可以对密文进行解密, 也就是说加密和解密,可以用同一个密钥, 速度比较快;
常用的对称加密方法有:
- DES
- 3DES
- AES
非对称加密
定义一对公钥 publicKey
和私钥 privateKey
, 可以使用私钥加密、公钥解密, 同理也可以使用公钥加密、私钥解密, 速度非常慢;
常见非对称加密方式的有:
- RSA (最常用)
- DSA
非对称加密的用途:
- 加密 / 解密;
- 签名 / 验签 (身份认证);
单向加密
不可逆加密, 对明文的加密产生一个密文, 不能再通过密文解出对应的明文, 一般用于计算消息摘要;
常见的单向加密有:
- MD5
- SHA (SHA-128、SHA-256 等)
秘钥交换协议
- Diffie-Hellman:
- 依赖于计算有限群的离散对数的困难性;
- 运算速度相对快;
- 支持前向保密;
- ECDHE: 基于椭圆曲线 ECC 的 Diffie-Hellman, 使用椭圆曲线上的点作为公钥和私钥
- 依赖于计算椭圆曲线离散对数的困难性;
- 运算速度比传统的 DH 更快, 安全性也更高;
- 支持前向保密;
- RSA: 除了用于非对称加密, 也可用于秘钥交换
- 依赖于大数分解问题的困难性;
- 运算速度相对慢;
- 不支持前向保密;
安全传输的原理
https 安全传输的过程用一句话概述为: 用对称加解密实现内容的安全传输, 用非对称加解密 (或专用秘钥交换协议) 实现对称加密秘钥的安全传输;
这么做主要是出于性能的考虑:
- 由于目标报文内容巨大, 故使用速度快的对称加密;
- 而对称加密秘钥的传输内容简短, 故可以容忍使用速度慢的非对称加密 (或专用秘钥交换协议);
以下我将用 6 个最关键的问题, 基于自然语言描述安全传输的核心逻辑:
- 如何将通信内容安全地传输给对方?
答: 用对称加密的方式进行通信; - 如何将对称加密的秘钥 secretKey 安全地传输给对方?
方案一: 使用专用的秘钥交换协议 (例如 ECDHE, 两端通过特定算法分别自主计算出相同的秘钥);
方案二: 用非对称加密的方式:- 服务端将公钥 publicKey 明文传输给客户端;
- 客户端随机生成一个对称加密的秘钥 secretKey;
- 客户端用 publicKey 对 secretKey 加密, 并传给服务端;
- 服务端用 privateKey 解密出 secretKey;
- 服务端如何将真实的公钥 publicKey 传输给对方?
答: 使用 CA 颁发的数字证书验证 publicKey 真伪:- 服务端将包含公钥 publicKey 的证书发送给客户端;
- 客户端验证证书的真伪;
- 客户端从证书中提取网站的公钥 publicKey;
- 客户端如何验证数字证书的真伪 (防篡改)?
答: 客户端对数字证书验签:- 客户端用 CA 的公钥对证书中的签名解密得到摘要 D1;
- 客户端用证书中的摘要算法, 对证书内容计算出摘要 D2;
- 若 D1 == D2 则验证通过;
- 如何确保 CA 的公钥是真实的?
答: CA 为自己的公钥专门生成的证书已提前内置在操作系统中了, 无需从网络中获取; - 如何生成域名的数字证书?
答: 网站提交指定材料, 向 CA 机构申请数字证书:- CA 向证书中写入摘要算法、域名、网站的公钥等重要信息;
- CA 根据证书中写入的摘要算法, 计算出证书的摘要;
- CA 用自己的私钥对摘要进行加密, 计算出签名;
- CA 生成一张数字证书, 颁发给指定域名;
- 网站的管理员, 把证书放在自己的服务器上;
用一张图来形象概括上述 6 个问题提及的知识点:
数字证书
数字证书 (Digital Certificate) 是一种用于验证网络实体 (如个人、设备、服务器等) 身份的电子凭证, 类似于现实生活中的身份证或护照; 它基于公钥基础设施 (PKI,Public Key Infrastructure) 技术, 确保通信双方的身份真实性 (确保客户端访问的是真实的网站而非钓鱼网站) 和数据传输的安全性;
证书的内容
一个标准的数字证书通常包含以下信息:
- 持有者信息: 名称、组织等;
- 颁发者信息: 证书颁发机构 (CA) 的名称;
- 有效期: 证书的生效和过期时间;
- 公钥 (Public Key): 用于加密数据或验证签名;
- 数字签名: 由 CA 对证书内容进行签名, 防止伪造;

证书颁发机构
由上文可知, 由于窃听者 / 中间人的存在, 我们无法信任公网传输的任何信息, 这就形成了一个无解的猜疑链:
- 我怎么知道秘钥 secretKey 是否安全得传给对方?
- 我怎么知道对方传输的公钥 publicKey 是真实的?
- 如果要引入一个权威的公证人来证明 publicKey 的真实性, 我又如何知道这个公证人本身是没问题的?
- ……
要想打破这个猜疑链, 就必须要在源头上建立起对公证人权威的信任, 于是现代主流的操作系统都内置了主流证书颁发机构 (Certificate Authority) 的公钥, 只要我们使用的是正版操作系统, 就可以放心使用 CA 的 publicKey 来验证服务端传输的数字证书的真伪;
SSL / TLS 协议
TLS (Transport Layer Security) 传输层安全性协议, 它的前身是 SSL (Secure Sockets Layer) 安全套接层, 是一个被应用程序用来在网络中安全的通讯协议, 它实现了将应用层的报文进行加密后再交由 TCP 进行传输的功能;
TLS 基于 TCP, 实现了两个应用进程之间的安全传输连接:
- 完成身份鉴别 (鉴别服务端或客户端);
- 安全地共享一对协商密钥 (主密钥) 来进行对称加密;
- 保证报文的完整性, 防篡改;
- 预防恶意的重放攻击;
协议栈总览
- TLS 握手协议: 用于加密、身份鉴别;
- TLS 记录协议: 用于保证报文的完整性和防重放攻击;


TLS 握手
TLS 握手协议用于实现在进行安全传输之前必要的身份鉴别和协商共享密钥:
握手协议的信息交换是在没有加密的情况下进行的, 在这一协议中所收发的所有数据都可能被窃听者窃听 (当然此阶段不传输真实报文, 即使被窃听也不用担心);
密码套件 (Cipher Suites)
由上文我们知道, https 的建立过程涉及到如下四个逻辑:
- 密钥交换 (Key Exchange): 生成需要的密钥;
- 身份认证 (Authentication): 验证 Server 身份;
- 对称加密 (Symmetric Encryption): 为数据传输提供保密性;
- 摘要算法 (Hashing): 数据完整性校验;
以上每个部分都可以使用不同的、可替换的算法实现, 如果要穷举所有的组合可能性, 其组合总数将会爆炸, 为了在 client - server 两端就以上四点快速达成一致协议, 就产生了密码套件的概念 (TLS 协议不允许用户对局部某个算法进行自定义, 只能协商选择一个密码套件);
在 Internet Assigned Numbers Authority 中详细枚举了所有的密码套件, 以下是几种常见的密码套件:
其中关于秘钥交换协议的对比:
- RSA:
- RSA 的客户端 pre-master 需要通过网络传输发送给服务端, 一旦服务器的私钥泄露, 会话密钥就会被破解;
- TLS 完成四次握手后, 才能进行应用数据传输;
- ECDHE (更加先进):
- 秘钥是两端独立计算出来的, 不会在网络上传输, 不存在直接泄漏的可能;
- 客户端可以不用等服务端的最后一次 TLS 握手, 就提前发出加密的 HTTP 数据, 节省了一个 RTT;
现代主流的 TLS 1.3 已淘汰 RSA, 默认使用 ECDHE 作为秘钥交换协议;
TLS 握手协议详细过程
- pre-master secret: 客户端随机生成的一个 48 字节 (384 位) 的临时秘钥, 其格式为:
- 前 2 字节为 TLS 版本号 (如 0x0303 代表 TLS 1.2);
- 后 46 字节为随机数据;
- pre-master 的安全传输:
- RSA 秘钥交换: 非前向保密;
- ECDHE 秘钥交换: 前向保密;
- master secret: 生成最终对称加密秘钥的 secret
- client / server 互相明文交换 random 随机数;
- 通过伪随机函数 PRF 生成:
PRF(pre-master, "master secret", client.random + server.random)
TLS 握手协议的详细过程如下:
多级秘钥: pre-master / master
由上图可见, TLS 的秘钥交换协议并非直接交换对称加密秘钥或相关 secret, 而是区分出了 pre-master / master secret, 如此设计的原因如下:
提高安全性, 防止密钥单一依赖:
- master Secret 依赖更多随机因素:
- master secret 由 Pre-master secret + 客户端随机数 (ClientRandom) + 服务器随机数 (ServerRandom) 通过 PRF (伪随机函数) 计算得出;
- 如果直接传输 master secret,攻击者截获后就能直接解密通信。
- 而通过 pre-master secret 计算 master secret, 增加了额外随机数 (ClientRandom 和 ServerRandom), 即使 pre-master 被破解, 仍需这两个随机数才能推导会话密钥, 提高安全性;
- 防止重放攻击:
- 如果 master secret 直接传输,攻击者可能记录握手过程并重放,导致相同的 master secret 被多次使用;
- 但 master secret 是由握手阶段的随机数动态生成的,每次握手都会不同,即使相同的 pre-master secret 也无法恢复相同的会话密钥;
- master Secret 依赖更多随机因素:
增强前向保密:
- pre-master secret 可以临时生成:
- 在 TLS 1.2 及之前,如果使用 RSA 密钥交换,pre-master secret 可能被服务器私钥解密,导致历史通信被破解 (无 PFS);
- 但 ECDHE/DHE 允许 pre-master secret 通过临时密钥计算得出,即使服务器私钥泄漏,也无法解密过去的 pre-master secret;
- 如果直接传输 master secret, 则无法实现这种前向保密机制;
- TLS 1.3 已淘汰 RSA 密钥交换, 默认使用 ECDHE, 确保 pre-master secret 具备 PFS;
- pre-master secret 可以临时生成:
防止中间人篡改密钥:
- master secret 依赖于握手阶段的随机数:
- 如果攻击者试图篡改 ClientRandom 或 ServerRandom, 会导致双方计算出的 master secret 不同, 握手失败;
- 而如果直接传输 master secret, 攻击者可能篡改它导致密钥被控制;
- master secret 依赖于握手阶段的随机数: