明文 HTTP 的三个风险
HTTP 的报文在网络上以明文传输,中间任何一个节点都能:
| 风险 | 后果 |
|---|---|
| 窃听 | 密码、Cookie、身份证号被读取 |
| 篡改 | 返回的页面里被插入广告或恶意脚本 |
| 冒充 | 用户以为自己连的是银行,其实是钓鱼站 |
HTTPS 要同时解决这三个问题,分别对应机密性、完整性、身份认证。
两种加密方式的分工
这是理解 HTTPS 的关键,也是很多人搞混的地方。
对称加密:加解密用同一把密钥。速度快,适合传大量数据。但问题是——怎么把密钥安全地给对方?
非对称加密:公钥加密、私钥解密。解决了密钥分发问题,但速度慢几百倍,不适合传数据。
HTTPS 的答案是两者结合:
1. 用非对称加密,安全地协商出一把「会话密钥」
2. 之后的全部数据用这把会话密钥做对称加密
一句话总结:非对称加密只用来协商密钥,对称加密用来传数据。
会话密钥是怎么协商的
早期用 RSA 直接加密会话密钥,现在主流是 ECDHE,它的好处是前向安全:
即使服务器的私钥将来泄露,攻击者也无法解密之前录下的历史流量。因为每次会话的密钥是双方临时算出来的,从不在网络上传输。
这也是为什么现在配置 TLS 时推荐 ECDHE 套件。
证书链:信任是怎么建立的
非对称加密解决不了「公钥是谁的」这个问题。如果中间人把自己的公钥发给客户端并冒充服务器,客户端根本分辨不出来。
证书解决的就是这件事:由受信任的第三方给公钥签名。
根证书(内置在操作系统 / 浏览器里,天然信任)
↓ 签名
中间证书(由根证书签发)
↓ 签名
服务器证书(包含域名和公钥,由中间证书签发)
浏览器验证时逐级向上验签,直到找到一个自己信任的根证书。根证书是预先内置的,这就是整条信任链的起点。
所以证书不是「加密」,而是身份的担保。
为什么中间人攻击失效
假设攻击者劫持了流量:
- 他需要伪造一张
example.com的证书给客户端 - 但证书必须由受信任的 CA 签名,他没有 CA 的私钥
- 他自己签的证书,浏览器验签失败,直接报警告
这就是为什么自签名证书在浏览器里会报错——它缺的正是可信的签名链。
握手过程简化版
客户端 服务端
|--- ClientHello ------------->| 支持的版本、套件、随机数
|<-- ServerHello + 证书 -------| 选定的套件、随机数、证书链
|--- 密钥交换参数 ------------->| (ECDHE 公钥)
|<-- 完成 ---------------------|
|<====== 对称加密传输数据 =====>|
TLS 1.3 把这个过程压缩到一个往返,还支持 0-RTT 恢复,这也是它比 1.2 快的原因。
常见配置误区
| 误区 | 问题 | 正确做法 |
|---|---|---|
| 只配 HTTP,不加跳转 | 用户仍可能走明文 | 配 301 强制跳转 HTTPS |
| 混用 HTTP 和 HTTPS | 页面里混入 HTTP 资源会被浏览器拦截 | 所有资源都用 HTTPS 或协议相对写法 |
| 用自签名证书上线 | 所有访客看到安全警告 | 用正规 CA 证书 |
| 证书到期没续 | 全站不可访问 | 配置自动续期并监控到期时间 |
| 只开 TLS 1.0 | 存在已知漏洞 | 至少 TLS 1.2,优先 1.3 |
还有一个容易忽略的点:HTTPS 之后,反向代理必须透传真实协议头。
proxy_set_header X-Forwarded-Proto $scheme;
后端据此判断当前是不是 HTTPS,从而决定下发的 Cookie 要不要带 Secure 标记。少了这个头,HTTP 环境下 Cookie 写不进去,用户会陷入「登录了又没登录」的循环。
小结
HTTPS = 非对称加密协商密钥 + 对称加密传数据 + 证书链证明身份。三者缺一不可。
工程上最容易出错的地方不在加密本身,而在配置的细节:强制跳转、协议头透传、证书续期。