九个问题从入门到熟悉 HTTPS
Category(分类): NET Protocol Status: 优
本文以九个问题为线索,介绍 HTTPS 的基本原理、证书信任、密钥协商和性能影响。原文中使用了“SSL/TLS”“公钥加密对称密钥”等较早期的简化说法,本文进行了修正:现代 HTTPS 主要使用 TLS 1.2 或 TLS 1.3,TLS 1.3 通常通过临时 Diffie-Hellman(ECDHE)协商会话密钥,而不是直接传输最终的对称密钥。
Q1:什么是 HTTPS?
答:HTTPS 是运行在 TLS 之上的 HTTP
HTTPS 可以理解为 HTTP over TLS。HTTP 负责请求方法、状态码、请求头、响应头和内容等语义,TLS 负责在 HTTP 与 TCP 之间提供加密传输、完整性保护和身份认证能力。
早期的 SSL 已经被 TLS 取代,现代 HTTPS 通常使用 TLS 1.2 或 TLS 1.3。可以把一次 HTTPS 通信大致分为两部分:
- TLS 握手:协商版本和密码套件,验证服务器身份,并协商出后续通信所需的密钥;
- TLS 记录层传输:使用协商出的对称密钥保护 HTTP 数据。
HTTPS 并不是一种新的 HTTP 方法,也不是“把 HTTP 内容简单加密后发送”。它是在 HTTP 语义外增加了一层安全传输协议。
Q2:你说的信息传输安全是什么意思?
答:通常包括机密性、完整性和身份认证
1. 机密性
客户端和服务器之间传输的应用数据应当只有通信双方能够理解。即使第三方截获了 TLS 密文,也不能在没有密钥的情况下还原出 HTTP 内容。
但 HTTPS 不能隐藏所有信息。网络观察者通常仍可能看到 IP 地址、端口、连接时间、数据包大小和流量方向等元数据;DNS 查询、SNI 等信息也可能根据配置暴露部分访问目标。
2. 完整性
第三方即使无法理解密文,也可能尝试修改或注入数据。因此客户端和服务器需要能够发现数据是否被篡改。
现代 TLS 通常使用 AES-GCM、ChaCha20-Poly1305 等 AEAD 算法,同时提供机密性和完整性保护。篡改 TLS 记录后,接收方验证失败,不会把伪造内容交给 HTTP 层。
3. 身份认证
客户端需要确认自己连接的确实是目标服务器,而不是攻击者伪造的服务器。TLS 通常通过 X.509 证书、可信 CA 证书链、域名匹配和握手签名来验证服务器身份。
这三个目标是相互关联但彼此独立的。HTTPS 不能解决服务器本身被入侵、客户端被恶意软件控制、密码被用户泄露等端点安全问题,也不能保证服务永远可用。
Q3:这么多要求,一个一个去满足是不是很复杂?
答:不能忽略服务器身份认证
原文中说“第三个要求可以不用管”,这是错误的。加密并不会自动带来身份认证。
如果客户端和攻击者建立了一条加密连接,这条连接同样可能具备机密性和完整性,但客户端加密的数据实际上会发送给攻击者。攻击者再与真正服务器建立另一条连接,就能在中间转发和查看数据,这就是中间人攻击(MITM)。
因此,安全的密钥协商必须与身份认证结合:
- 证书证明某个公钥属于目标域名;
- CA 的数字签名保护证书内容;
- TLS 握手签名证明通信对端确实持有证书对应的私钥;
- 客户端验证证书链、域名、有效期和用途后,才继续建立安全连接。
Q4:那怎么加密信息呢?
答:应用数据使用对称加密,身份认证和密钥协商使用非对称密码学
4.1 对称加密
对称加密使用同一个秘密密钥进行加密和解密。它可以理解为对原始数据进行可逆变换,例如把 Hello 变换成 Ifmmp 的例子可以帮助初学者理解“有密钥才能还原”,但这种简单的字母移位算法极其不安全,不能用于真实通信。
实际 TLS 通常使用 AES-GCM 或 ChaCha20-Poly1305 等 AEAD 算法。对称加密速度快、适合处理大量应用数据,因此 HTTP 请求和响应主体通常使用对称密钥保护。
4.2 非对称密码学
非对称密码学使用一对密钥:公钥可以公开,私钥必须由持有者保管。RSA 可以利用大整数分解困难性构造安全方案,椭圆曲线算法则依赖椭圆曲线离散对数等数学问题。不能把所有非对称算法都简单归结为“大整数分解”。
非对称密码学主要有两类用途:
- 公钥加密:使用公钥加密,通常由对应私钥解密,用于机密性;
- 数字签名:使用私钥签名,其他人使用公钥验证,用于身份认证和完整性。
“私钥加密、公钥解密”是对数字签名的过度简化,实际文章中应使用“私钥签名、公钥验证”来描述。TLS 并不是用服务器私钥加密所有应用数据,而是使用证书签名验证身份,再通过密钥协商得到对称会话密钥。
Q5:对称密钥如何传输?
答:现代 TLS 通常通过 ECDHE 协商共享秘密,而不是直接传输最终密钥
如果服务器直接明文返回对称密钥,监听者拿到这个密钥后就能解密后续通信。因此,最终会话密钥不能通过明文发送。
现代 TLS 1.3 通常使用临时 Diffie-Hellman,实际常见形式是 ECDHE。客户端和服务器分别生成临时密钥对,并交换公钥参数:
- 客户端发送
ClientHello,其中可以包含支持的 TLS 版本、密码套件、随机数和 ECDHEkey_share; - 服务器发送
ServerHello和自己的key_share,双方根据各自的私密参数计算相同的共享秘密; - 服务器通过证书和
CertificateVerify消息证明自己拥有对应私钥; - 双方使用 HKDF 等密钥派生机制,从共享秘密和握手上下文派生出 TLS 记录层使用的会话密钥;
- 握手完成后,HTTP 数据使用高效的对称加密传输。
整个过程中,最终的对称会话密钥并没有直接在网络上传输,监听者即使看到了双方交换的公开参数,也不能仅凭这些参数计算出共享秘密。
TLS 1.2 曾经支持 RSA 密钥交换:客户端生成 premaster secret,并用服务器证书中的 RSA 公钥加密后发送给服务器,服务器使用私钥解密。这是历史方案,缺少前向保密性,现代 TLS 1.3 已经移除了静态 RSA 密钥交换,推荐使用临时 Diffie-Hellman。
Q6:那服务器公钥怎么传输?
答:服务器通过 X.509 证书发送公钥和身份信息
服务器证书不是“用 CA 私钥加密后的公钥”,而是一份由 CA 数字签名的结构化数据。证书通常包含:
- 服务器的公钥;
- 证书主体和签发者信息;
- 域名等身份信息,现代证书主要通过 Subject Alternative Name(SAN)表示;
- 有效期;
- 密钥用途和扩展用途;
- CA 对证书内容的数字签名。
服务器通常会在 TLS 握手中发送自己的终端证书以及必要的中间 CA 证书。客户端并不是“用 CA 公钥解密证书”,而是使用本地信任库中的 CA 公钥验证证书签名,并构建一条从服务器证书到可信根证书的证书链。
客户端还需要检查:
- 证书链是否能够连接到本地信任的根 CA;
- 请求的域名是否匹配证书的 SAN;
- 证书是否在有效期内;
- 证书是否允许用于服务器身份认证;
- 证书是否被撤销或被本地安全策略禁止使用。
证书链中的根证书通常已经预置在操作系统、浏览器或应用程序的信任库中,服务器一般不需要再次发送根证书。企业内网也可以使用自己管理的私有 CA,但客户端必须明确安装并信任该 CA。
Q7:怎么知道证书有没有被篡改?
答:通过 CA 的数字签名和证书链验证
单纯把证书的哈希值和证书一起传输并不能防止篡改,因为攻击者可以同时修改证书和哈希值。TLS 使用的是数字签名:
- CA 对证书中的主体、公钥、域名、有效期等内容计算摘要并使用 CA 私钥签名;
- 客户端使用 CA 公钥验证签名;
- 如果证书内容被修改,原来的 CA 签名通常就无法验证通过;
- 客户端还要检查证书链、域名和有效期,签名正确并不代表证书一定适用于当前网站。
TLS 1.3 握手中,服务器还会发送 CertificateVerify,使用证书对应的私钥对握手 transcript 进行签名。客户端验证这个签名,可以确认对端确实持有该证书的私钥,而不是只拿到了一份证书副本。
握手完成时的 Finished 消息以及后续 AEAD 记录校验,还可以检测握手过程和应用数据是否被篡改。
哈希算法仍然非常重要,但它通常作为数字签名、密钥派生和完整性验证的一部分使用。哈希值本身不提供身份认证,也不能替代 CA 签名。
Q8:这样可以防止第三方冒充服务器吗?
答:在客户端正确验证证书且信任根未被破坏时,可以有效防止常见的中间人冒充
当客户端访问目标域名时,攻击者即使截获通信,也不能仅凭自己的密钥生成一张能够通过客户端证书链和域名检查的证书。客户端会检查证书是否由可信 CA 链签发,以及证书中的 SAN 是否包含当前访问域名。
但以下情况可能让攻击者获得“被客户端信任”的能力:
- 用户手动安装了攻击者控制的根证书;
- 操作系统、浏览器或企业代理的信任库被恶意修改;
- 用户忽略证书错误或关闭证书校验;
- 可信 CA 被攻破或错误签发证书;
- 客户端本身被恶意软件控制。
所以不要随便安装来源不明的根证书,也不要为了访问网站而忽略证书错误。根证书一旦被安装到信任库中,拥有对应私钥的一方就可以为任意域名签发客户端信任的证书。
Charles 等 HTTPS 调试工具的原理
Charles、mitmproxy 等调试工具通常要求用户在设备上安装它们的本地根 CA 证书。以 Charles 为例,通信过程大致是:
- 客户端与 Charles 建立一条 TLS 连接;
- Charles 为目标域名生成一张临时证书,该证书由 Charles 根 CA 签发;
- 客户端因为信任 Charles 根 CA,所以接受这张临时证书;
- Charles 再作为客户端与真正的服务器建立另一条 TLS 连接,并验证真正服务器的证书;
- Charles 在两段 TLS 连接之间解密、查看并重新加密数据。
因此,调试工具不是直接把真实服务器的证书拿来复用,而是在本地终止并重新建立两段 TLS 连接。Charles 根 CA 的私钥如果泄露,信任该根证书的设备就可能遭受中间人攻击,因此调试证书只应安装在受控的开发或测试设备上。
EV 证书
EV(Extended Validation)证书需要更严格的组织身份审核,但它不会让加密算法更强,也不会改变 TLS 的基本机密性。现代主流浏览器已经弱化或移除了地址栏中对 EV 企业名称的突出显示,因此不能把“地址栏显示公司名称”作为 EV 证书的可靠判断标准。原文以 Bitbucket 官网 作为示例,但当前浏览器的展示效果可能已经不同。
Q9:HTTPS 握手会影响性能吗?
答:会产生一定开销,但连接复用和会话恢复可以降低影响
HTTPS 的额外开销主要来自连接建立和 TLS 握手,而不是每个数据包的对称加解密。现代 CPU 通常可以高效执行 AES-GCM 或 ChaCha20-Poly1305,但证书链验证、密钥协商和握手往返仍然需要时间。
需要区分 TCP 握手和 TLS 握手:
- TCP 三次握手通常按约 1 个 RTT 估算;
- TLS 1.2 完整握手通常还需要约 2 个 RTT;
- TLS 1.3 完整握手通常还需要约 1 个 RTT;
- TLS 会话恢复可以减少往返,TLS 1.3 还可以使用 0-RTT 早期数据,但 0-RTT 存在重放风险,只适合可安全重复执行的请求。
如果连接使用持久连接,多个 HTTP 请求可以复用同一条 TCP + TLS 连接,不需要为每个请求重复握手。TLS 会话票据和 PSK 也可以帮助客户端恢复之前的会话状态,但恢复会话不等于永久复用旧的对称密钥。
HTTP/2 的协商通常可以通过 TLS 的 ALPN 在握手阶段完成。浏览器访问的 HTTP/2 通常是 HTTPS,但 HTTPS 和 HTTP/2 属于不同层次:HTTPS 负责 TLS 安全传输,HTTP/2 负责 HTTP 语义的二进制分帧和多路复用。启用 HTTP/2 仍可能产生协议处理、流调度和服务器资源开销,不能说从 HTTPS 切换到 HTTP/2“完全没有性能成本”。
综合来看,HTTPS 确实比直接使用 HTTP 多了一定握手和计算成本,但在连接复用、会话恢复、HTTP/2 多路复用以及硬件加速的帮助下,实际开销通常可以接受。对于登录、支付和涉及隐私的通信,传输安全的重要性通常远高于这部分成本。
总结
- HTTPS 是 HTTP over TLS,不是一个新的 HTTP 方法。
- HTTPS 主要提供机密性、完整性和服务器身份认证。
- 加密不能自动完成身份认证,未经认证的加密连接仍可能遭受中间人攻击。
- 现代 TLS 通常使用 ECDHE 协商共享秘密,再使用对称 AEAD 算法传输应用数据。
- 证书是由 CA 数字签名的身份与公钥绑定信息,不是简单的“加密公钥”。
- 客户端必须验证证书链、域名、有效期和用途,不能只检查证书是否存在。
- Charles 等调试工具通过安装本地根证书,在客户端和真实服务器之间建立两段 TLS 连接。
- TLS 会增加握手延迟,但连接复用、会话恢复和 TLS 1.3 可以降低实际影响。