跳到正文

HTTPS 与密码学基础 ​

一句话:TLS 用非对称手段解决「和陌生人安全地协商一把临时对称密钥」,再用对称加密搬运数据;证书链把「这把公钥属于谁」的信任从 CA 逐级传到站点,代价是链路更长、证书运维成为新的故障面。

适用版本:TLS 1.2(RFC 5246)、TLS 1.3(RFC 8446)、OpenSSL 3.x。算法参数与套件支持范围以官方文档为准。

为什么需要 ​

明文 HTTP 同时暴露三件事:内容可被窃听、可被篡改、对端可被冒充。只靠对称加密解不了「第一把密钥怎么安全送到对方」;只靠非对称加密则太慢,无法承载大量数据;只靠哈希只能发现改动,既不能保密,也不能证明是谁发的。HTTPS 把三者组合起来,各自只做擅长的事。

核心机制 ​

三类原语:各自解决什么,边界在哪 ​

原语解决不解决代价典型用法
对称加密大量数据的机密性密钥怎么安全分发密钥管理复杂AES-128/256-GCM、ChaCha20-Poly1305、SM4
非对称加密密钥分发、身份绑定大流量加密(慢几个数量级)密钥长、运算重ECDHE 密钥交换、RSA-OAEP、签名
哈希完整性、唯一摘要机密性、身份认证有碰撞概率SHA-256/SHA-3、口令派生、签名前摘要

三条边界必须分清:

  • 哈希不是加密。它没有密钥、不可逆,只保证「改过就能发现」。把口令直接做 SHA-256 仍然会被彩虹表和 GPU 爆破,正确做法是加盐并用慢速 KDF(Argon2id、scrypt、bcrypt)。
  • 哈希也不等于认证。普通哈希谁都能重算,必须用带密钥的 HMAC,或用私钥做数字签名,才能让对端确认来源。
  • 非对称不拿来加密业务数据。TLS 里它只做两件事:ECDHE 协商出会话密钥,证书/签名证明公钥归属;真正的大流量交给对称 AEAD。

对称加密选 AEAD(带关联数据的认证加密),因为它一次给出机密性和完整性。AES-GCM 的硬约束是 nonce 绝不能在同一密钥下重复,否则可恢复认证密钥;CBC 需要额外 MAC 且历史上反复出现 Padding Oracle,TLS 1.3 已移除 CBC。

TLS 握手:1.2 与 1.3 差在哪 ​

TLS 1.2 完整握手是 2 个 RTT:ClientHello/ServerHello 与证书一个往返,ClientKeyExchange/ChangeCipherSpec/Finished 再一个往返;会话复用时才能降到 1 个 RTT。TLS 1.3 把密钥交换材料直接放进 ClientHello,完整握手 1 个 RTT 完成,恢复会话时可用 PSK 做 0-RTT。

维度TLS 1.2TLS 1.3
完整握手2-RTT(恢复 1-RTT)1-RTT(恢复可 0-RTT)
密钥交换RSA 或 ECDHE仅 (EC)DHE,前向安全强制
密钥派生PRF(Master Secret)HKDF 密钥调度
证书消息明文ServerHello 之后全部加密
密码套件算法组合多,易配错仅 5 个,认证/密钥交换与记录层算法分离
已移除—RSA 密钥交换、CBC、RC4、3DES、重协商

TLS 1.3 的 1-RTT 来自「客户端先猜一组 ECDHE 参数并随 ClientHello 发出」;服务端选定后立即能算出共享密钥,因此证书和 Finished 可以同批加密返回。0-RTT 则是把恢复密钥和早期数据一起发,早期数据可被重放,只能用于幂等请求,且服务端要能拒绝。

两者都不保护「端点已经被攻破」的情况:TLS 只覆盖传输段,落盘、日志、内存转储仍要单独加密。

证书链:信任是怎么传递的 ​

浏览器/操作系统内置受信 Root CA;Root 签发 Intermediate,Intermediate 签发站点叶子证书。客户端验证时做六件事:

  1. 用 Issuer 字段和随握手下发的 Intermediate 证书构建到受信 Root 的路径。
  2. 逐级用上一级公钥验证下一级签名。
  3. 检查每级有效期(notBefore/notAfter)。
  4. 检查叶子证书的 SAN 是否匹配访问域名;CN 仅作兼容,现代校验以 SAN 为准。
  5. 检查 Intermediate 的 basicConstraints CA:TRUE、keyUsage 与路径长度限制。
  6. 检查吊销状态(CRL/OCSP,生产优先 OCSP Stapling)与公开 CA 的 CT 日志(SCT)。

最常见的线上故障不是算法被攻破,而是 服务端没下发 Intermediate:桌面浏览器可能靠缓存补链,移动端或 Java 客户端直接报「unable to find valid certification path」。SNI 则是另一类:同一 IP 托管多个站点时,不带 -servername 会拿到默认站点的证书。

国密落地:替换算法不等于替换体系 ​

国密类型对应国际算法关键参数
SM2椭圆曲线公钥算法ECDSA/ECDH256-bit 密钥,签名与密钥交换
SM3密码杂凑SHA-256输出 256-bit
SM4分组密码AES128-bit 分组 + 128-bit 密钥(16 字节)
SM9标识密码(IBE)无直接对应以用户标识派生公钥

SM4 的密钥固定 16 字节,CBC 模式 IV 也是 16 字节;不存在「SM4 用 32 字节密钥」的用法。若业务要求 256-bit 密钥强度,应换 AES-256 或采用合规的组合方案,而不是给 SM4 塞 32 字节密钥。国密 TLS(TLCP,GB/T 38636-2020)与标准 TLS 是两套协议栈,不能把 SM4 直接填进 TLS 1.3 的套件列表;具体模式与参数以 GB/T 32907、GM/T 0002、GM/T 0081 等标准为准。

工程上常见的是双层密钥:KMS 生成 128-bit DEK 并用 SM2 加密传给网关,网关再用每个应用独有的 KEK(16 字节 SM4 密钥 + 16 字节 IV)二次加密,应用本地解出 DEK 后做业务加解密。网关全程不持有 DEK 明文,泄露面从「所有应用」收敛到「单个应用」。高安全场景还会把 SM2 私钥拆成两片,客户端与服务端各持一片做联合签名,单点被攻破也签不出完整签名。

最小上手 ​

bash
# OpenSSL 3.x:验证证书链、主机名,并让校验失败直接返回非 0
openssl s_client -connect example.com:443 -servername example.com \
  -showcerts -verify_hostname example.com -verify_return_error </dev/null
# 期望输出包含:Verify return code: 0 (ok)

# 只看叶子证书的关键字段
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

# 强制 TLS 1.3,确认协议与套件
openssl s_client -connect example.com:443 -servername example.com -tls1_3 </dev/null 2>&1 \
  | grep -E "Protocol|Cipher"

-servername 是 SNI,不带它测共享 IP 会得到错误证书;-verify_return_error 让校验失败变成非 0 退出码,适合放进巡检脚本。服务端至少应收口到:

nginx
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

TLS 1.3 的套件由 ssl_conf_command Ciphersuites ... 单独配置,ssl_ciphers 只影响 1.2;具体指令以所用 Nginx/OpenSSL 版本为准。

生产动作 ​

  • 协议与套件:只开 TLS 1.2/1.3,禁用 RSA 密钥交换、CBC、RC4、3DES;用 nmap --script ssl-enum-ciphers 或内部扫描确认没有回退。
  • 证书生命周期:叶子证书剩余 30 天告警,续期失败单独告警;证书必须带完整 Intermediate,自动化部署后跑一次 openssl s_client 验收。
  • HSTS 顺序:先确认全站和子域都能 HTTPS,再开 includeSubDomains; preload;一旦 preload,回退 HTTP 的窗口以 max-age 为准,不能靠删响应头立刻恢复。
  • 会话恢复与 0-RTT:TLS 1.3 的 ticket 要能轮换;0-RTT 只给幂等 GET,非幂等请求在服务端拒绝早期数据。
  • 排障三段:握手失败 → openssl s_client -showcerts → 看是缺 Intermediate、证书过期、SNI/域名不匹配还是客户端信任库太旧;不要用「关闭证书校验」绕过。
  • 内部链路:服务网格用 mTLS 时,确认 Sidecar 确实在拦截流量,而不是「装了 Istio 就默认加密」;证书轮换失败会表现为大面积 503。

边界 ​

  • TLS 不保护落盘数据、日志和被攻破的端点;它只保证「客户端到 TLS 终止点」这一段。
  • 证书固定(pinning)能防错误 CA,但叶子证书轮换会让客户端集体失联;要固定就固定 Intermediate/公钥,并预留轮换窗口。
  • 自签名证书只适合受控内部链路,且必须显式分发信任锚;不要把它当「免费的 HTTPS」。
  • 国密替换是合规与生态选择,不代表同等参数下一定更强;客户端、网关、HSM 的支持矩阵要一起评估。
  • 不要自己实现密码协议或「把明文异或一下」;用成熟库的 AEAD 接口,并确保 nonce 唯一。

讲清楚 ​

HTTPS 解决的是「在不信任的网络上,和陌生人安全通信」。它先用证书确认对端身份,再用 ECDHE 协商一把本次会话专用的对称密钥,之后的数据全部用 AES-GCM 这类 AEAD 加密。非对称只负责身份和密钥分发,对称负责吞吐,哈希负责完整性和签名摘要,三者边界不能混。TLS 1.3 把密钥交换材料提前到 ClientHello,完整握手从 1.2 的 2 个 RTT 降到 1 个,强制前向安全并加密证书;代价是 0-RTT 有重放风险,只能用于幂等请求。生产上最常见的故障不是算法被破,而是证书链缺 Intermediate、SNI 不匹配或证书过期,所以巡检要直接跑 openssl s_client 看验证结果,而不是只看进程活着。

把一门技术讲透到既懂也会用