答案:HTTPS与TLS握手
为什么 TLS 握手先用非对称加密(RSA/ECDHE),后用对称加密(AES)传输数据?对称加密和非对称加密各有什么优缺点?
答案:
TLS 握手的设计是"各取所长"——非对称加密解决"密钥配送问题",对称加密解决"性能问题"。
为什么握手阶段用非对称加密?
客户端和服务器一开始没有任何共享秘密,如果直接传对称密钥,中间人就能截获。非对称加密的特性是:公钥可以公开传输,私钥只保存在服务器。客户端用服务器公钥加密"预主密钥",只有服务器私钥能解密,中间人即使截获也无法破解。这就安全地完成了对称密钥的协商。
飞翔公司的翼王曾让图妹做过一个实验:用纯 RSA 加密传输 100MB 的视频文件,结果 CPU 占用率飙到 90%,耗时是对称加密的 100 倍以上。
两种加密的对比:
| 特性 | 非对称加密(RSA/ECDHE) | 对称加密(AES) |
|---|---|---|
| 速度 | 慢(比对称加密慢 100~1000 倍) | 快(硬件加速,Gbps 级吞吐) |
| 密钥管理 | 简单(公钥公开,私钥保密) | 困难(N 个节点需要 N² 个密钥) |
| 用途 | 密钥交换、数字签名 | 大量数据传输 |
| 数学基础 | 大数分解/椭圆曲线离散对数 | 置换、替换、混淆 |
# 用 OpenSSL 实测性能差异
# 非对称加密(RSA 2048)性能
openssl speed rsa2048
# 典型结果:每秒约 2000 次签名验证
# 对称加密(AES-128-GCM)性能
openssl speed aes-128-gcm
# 典型结果:每秒数 GB 数据量
因此 TLS 握手完成后,双方协商出对称密钥(如 AES-128-GCM),后续所有 HTTP 数据都用这个密钥加密——既安全又高效。
假设某个 CA 机构被黑客攻破,能随意签发 www.feixiang.net 的假证书。HSTS 能防御这种攻击吗?证书固定呢?
答案:
HSTS 无法防御这种攻击。
HSTS(HTTP Strict Transport Security)的作用是强制浏览器只用 HTTPS 访问网站,防止用户被劫持到 HTTP 钓鱼页面。但它不验证证书是谁签发的——只要证书是"合法 CA 签发的、域名匹配、未过期",浏览器就信任。如果黑客攻破了 CA,签发的假证书满足以上所有条件,HSTS 完全无法识别。
证书固定(Certificate Pinning)可以防御。
证书固定是把服务器证书(或公钥)的指纹"钉"在客户端(浏览器或 App)里。客户端连接时,只信任指纹匹配的服务器证书,不信任任何 CA 链。
在飞翔公司的官方 App 中,星宇(移动端负责人)就实现了证书固定:
// Android 证书固定示例(Kotlin + OkHttp)
val certificatePinner = CertificatePinner.Builder()
.add("www.feixiang.net",
"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") // 真实证书指纹
.add("www.feixiang.net",
"sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=") // 备用证书指纹
.build()
val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()
如果 CA 被攻破,假证书的指纹与固定的指纹不匹配,App 会立即拒绝连接并报警。凌叔(安全负责人)在飞翔公司的安全策略是:HSTS 是基线要求,证书固定是 App 层的额外保险。
但证书固定也有风险:如果服务器证书正常轮换(到期更新),而客户端没更新指纹,就会导致合法用户也无法访问。因此需要固定"备用证书"的指纹,或者采用 HPKP(HTTP Public Key Pinning,但已被主流浏览器废弃,推荐在 App 层实现)。
凌叔发现官网启用 HTTPS 后,部分老客户端(旧版 Android)无法访问。可能是什么原因?如何在不降低安全性的前提下兼容这些客户端?
答案:
旧版 Android(如 Android 4.x)无法访问,最常见的原因是 TLS 版本和密码套件不兼容:
- TLS 版本过高:旧版 Android 只支持 TLS 1.0,而服务器配置了最低 TLS 1.2
- 密码套件不匹配:服务器只启用了 ECDHE + AES-GCM 等现代套件,老客户端不支持
- SNI(Server Name Indication)问题:极老的 Android 不支持 SNI,而 CDN/云负载均衡依赖 SNI 分发证书
诊断方法:
# 测试旧版 Android 支持的 TLS 版本
curl -v --tlsv1.0 https://www.feixiang.net
# 如果服务器拒绝,会显示:curl: (35) error:1409442E:SSL routines:tlsv1 alert protocol version
# 用 nmap 扫描服务器支持的密码套件
nmap --script ssl-enum-ciphers -p 443 www.feixiang.net
不降低安全性的兼容方案:
- 分层配置,多端口服务:
- 主域名
www.feixiang.net:严格 TLS 1.2+,现代密码套件(面向主流用户) - 兼容子域
legacy.www.feixiang.net:允许 TLS 1.0/1.1,但启用弱密码套件监控和限速(面向老客户端)
- 主域名
# Nginx 分层配置示例
server {
listen 443 ssl;
server_name www.feixiang.net;
ssl_protocols TLSv1.2 TLSv1.3; # 严格
ssl_ciphers 'ECDHE+AESGCM:ECDHE+CHACHA20';
}
server {
listen 4443 ssl;
server_name legacy.www.feixiang.net;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 兼容老客户端
ssl_ciphers 'ECDHE+AESGCM:ECDHE+AES:RSA+AES';
# 但限制该端口的访问频率和权限
}
CDN 边缘适配:使用 Cloudflare/AWS CloudFront 的"兼容模式",它们会自动根据客户端能力协商 TLS 版本,而不降低源站安全性。
客户端升级引导:检测到旧版 Android 时,返回一个友好的 HTML 页面提示用户升级系统或使用飞翔公司 App 的最新版本。
风速(运维工程师)在飞翔公司的实际做法是:通过 CDN 的 User-Agent 分析,发现受影响用户不到 0.1%,于是决定主站保持严格 TLS 1.2+,同时在 CDN 层对这部分用户做降级协商,并在页面顶部显示"您的设备版本过低,建议升级"的横幅。