通过未加密信道传输的数据不安全、不可信并且十分容易被截取。我们一直把保护用户的安全、隐私和数据完整视为自己的责任 —— 所有数据在传输和存储过程中都必须加密。自古以来,对性能的担忧常常被作为逃避这一义务的借口,但发展到今日,高性能与加密已经不再是势不两立的了。今天我们来辟一些谣。
创建和使用加密信道通信的过程,导致了额外的计算开销。首先是 TLS 握手过程中的非对称(公钥)加密。当共享密钥建立后,后续还要使用对称加密来处理数据的通信。
# 升级到最新版 $> openssl version OpenSSL 1.1.1a 20 Nov 2018 # 运行基准测试 $> openssl speed sha $> openssl speed ecdh
但好消息是,现代的硬件为了减小这些开销,已经做了长足改进。曾经可能需要专用附加硬件才能有效进行的运算,现在可以只用 CPU 高效地完成。
在我们的前线生产机器上,SSL/TLS 只产生了不到 1% 的 CPU 占用、单连接不到 10 KB 的内存使用和低于 2% 的网络开销。很多人以为 SSL/TLS 会耗费大量的 CPU 时间,我们希望前面提到的数字能够消除这种误解。
- Adam Langley, Google "Overclocking SSL"
我们已经使用软件与硬件负载均衡器结合的方式大规模部署了 TLS。我们发现现代的软件 TLS 已经快到,能够在普通商用 CPU 上处理大量 HTTPS 流量,而不需要借助专门的加密运算硬件。
- Doug Beaver, Facebook "HTTP2 Expression of Interest"
椭圆曲线密钥交换 (Elliptic Curve Diffie-Hellman (ECDHE)) 实现相同的安全级别的前提下,只比 RSA 开销大一点点…… 在实际的部署中,我们发现开启并优先使用 ECDHE 加密套件只造成了微乎其微的 CPU 占用增加。HTTP keepalives 和会话恢复功能意味着大多数请求实际上都不需要经过一个完整的握手流程,故握手操作并不大量占用我们的 CPU。我们发现 Twitter 75% 的客户端请求是通过 ECDHE 建立的连接传输的。剩下的 25% 主要包含暂时还不支持 ECDHE 加密套件的旧客户端。
- Jacob Hoffman-Andrews, Twitter "Forward Secrecy at Twitter"
在客户端和服务端可以通过 TLS 交换数据前,必须先协商建立加密信道,这导致了建立新连接时额外的往返通信(roundtrip)。然而实际上,并不是每次连接都必须承受一整套完整握手的开销:TLS 会话恢复 (resumption) 和 TLS 抢跑 (False Start) 功能能将客户连接开销降低到一个往返。
一个配置完好的 TLS 部署可以为用户体验带来巨大的正面效果,同时也能改善运作开销。这是部分关键的功能和概念:
为实现最佳性能,查阅 TLS 性能列表,并使用如 Qualys SSL Server Test 这样的工具来检测你的服务器是否有常见的配置缺陷或安全缺陷。
TLS 为服务器增添了许多新的参数和选项。我们的目标不是提供一个全面详尽的清单(需要的话,请查阅服务器文档),而是突出一些性能相关的重要功能:重启 (resumption)、装订 (stapling)、抢跑(false start)(需要 ALPN 与向前保密(forward secrecy))和对 HTTP/2 协议的支持。
会话标识符 | 会话 tickets | OCSP 装订 | 动态 record 大小 | ALPN | 向前保密 | HTTP/2 | TLS 1.3 | TLS 1.3 |
|
---|---|---|---|---|---|---|---|---|---|
Apache | 是 | 是 | 是 | 是 | 是 | 是 | 是 | 是 | 否 |
ATS | 是 | 是 | 是 | 动态 | 是 | 是 | 是 | 是 | 否 |
Caddy | 是 | 是 | 是 | 是 | 是 | 是 | 是 | 是 | 否 |
F5 BIG-IP | 是 | 是 | 是 | 是 | 是 | 是 | 是 | 是 | 否 |
H2O | 是 | 是 | 是 | 动态 | 是 | 是 | 是 | 是 | 是 |
HAProxy | 是 | 是 | 是 | 动态 | 是 | 是 | 是 | 是 | 是 |
Hitch | 是 | 是 | 是 | 否 | 是 | 是 | 是 | 是 | 否 |
IIS | 是 | 是 | 是 | 否 | 是 | 是 | 是 | 否 | 否 |
Citrix ADC | 是 | 是 | 是 | 否 | 是 | 是 | 是 | 是 | 否 |
lighttpd | 否 | 是 | 是 | 否 | 是 | 是 | 是 | 是 | 否 |
NGINX | 是 | 是 | 是 | 静态 (16k) | 是 | 是 | 是 | 是 | 是 |
node.js | 是 | 是 | 可选 | 可选 | 是 | 是 | 是 | 是 | 否 |
Go | 是 | 是 | 可选 | 是 | 是 | 是 | 是 | 是 | 否 |
nghttpx | 是 | 是 | 是 | 动态 | 是 | 是 | 是 | 是 | 是 |
Pulse Secure vTM | 是 | 是 | 是 | 否 | 是 | 是 | 是 | 是 | 否 |
ShimmerCat | 是 | 否 | 否 | 是 | 是 | 是 | 是 | 否 | 否 |
没有你最喜欢的服务器,或者发现了一个错误?发起一个 pull request!
使用 CDN 可以在更接近用户的位置处理请求,可显著降低 TCP 与 TLS 握手的开销 - 查阅 early termination。为实现最佳效果,你应该为静态内容和动态内容都开启 CDN。
会话标识符 | 会话 tickets | OCSP 装订 | 动态 record 大小 | ALPN | 向前保密 | HTTP/2 | TLS 1.3 | TLS 1.3 |
|
---|---|---|---|---|---|---|---|---|---|
Akamai | 是 | 是 | 是 | 可配置 (静态) | 是 | 是 | 是 | 是 | 否 |
AWS ELB (Classic) | 是 | 是 | 否 | 否 | 否 | 是 | 否 | 否 | 否 |
AWS ELB (Application) | 是 | 是 | 否 | 否 | 是 | 是 | 是 | 否 | 否 |
AWS CloudFront | 否 | 是 | 是 | 否 | 是 | 是 | 是 | 是 | 否 |
BelugaCDN | 是 | 是 | 是 | 动态 | 是 | 是 | 是 | 否 | 否 |
CDN77 | 是 | 是 | 是 | 动态 | 是 | 是 | 是 | 是 | 是 |
Cloudflare | 是 | 是 | 是 | 动态 | 是 | 是 | 是 | 是 | 是 |
ChinaNetCenter | 是 | 是 | 否 | 否 | 否 | 是 | 否 | 否 | 否 |
EdgeCast | 否 | 是 | 是 | 否 | 是 | 是 | 是 | 是 | 否 |
Fastly | 是 | 是 | 是 | 动态 | 是 | 是 | 是 | 是 | 仅客户到 Fastly |
Google App Engine | 是 | 是 | 否 | 动态 | 是 | 是 | 是 | 否 | 否 |
Heroku | 是 | 是 | 否 | 否 | 否 | 是 | 否 | 否 | 否 |
Imperva Incapsula | 是 | 是 | 是 | 动态 | 是 | 是 | 是 | 否 | 否 |
Instart | 是 | 是 | 是 | 可配置 (静态) | 是 | 是 | 是 | 是 | 是 |
KeyCDN | 是 | 是 | 是 | 可配置 (静态) | 是 | 是 | 是 | 是 | 是 |
Limelight | 是 | 是 | 可配置 | 否 | 是 | 是 | 是 | 是 | 否 |
StackPath | 是 | 是 | 是 | 否 | 是 | 是 | 是 | 是 | 否 |
Netlify | 是 | 是 | 否 | 动态 | 是 | 是 | 是 | 是 | 否 |
QUANTIL | 是 | 是 | 否 | 否 | 否 | 是 | 否 | 否 | 否 |
Vercel Edge Network | 是 | 是 | 是 | 否 | 是 | 是 | 是 | 是 | 否 |
没有你最喜欢的 CDN 和 PaaS,或者发现了一个错误?发起一个 pull request!
具体实现的质量很重要 —— 这点毋庸置疑 —— 所以你必须自己踏出这一步。也就是说,只有用符合真实情景的流量去测试你自己的硬件,才能知道什么配置对于你的具体负载而言表现最好。不要相信那些已经过期的基准测试结果,升级一下你的 OpenSSL 库,升级一下你的服务器,然后自己跑跑看。
不一定。一旦你开启并优化了 TLS 栈,你离部署 HTTP/2 就已经只有一步之遥了。与 HTTP/1.1 相比, HTTP/2 对每个 origin 只需要一个连接,也就意味着更少的 socket 数、内存 buffer、TLS 握手等等。结果就是,你很有可能反而能够用更少的资源处理更大的用户量。
一个可行的方案是采用 TCP 快速打开(Fast Open),使得可以在 TCP SYN 包内附带发送 ClientHello 请求 —— 从而减少一次往返。目前,TLS 1.3 和 QUIC 都在试验 “零往返”("zero-RTT")的握手机制。查阅 QUIC crypto doc 和 这一集 GDL 视频 获取对 QUIC 的大致介绍。
Mozilla 维护了一个包含推荐的加密算法列表和服务器配置技巧的维基页面。
会话恢复和抢跑都消除了一次 TLS 握手中的往返。此外,通过重用前一次会话的参数,会话恢复使得你能够直接跳过非对称握手加密过程 —— 从而节约 CPU。一句话说,是的,两个都要打开。
确保你使用了多服务器之间共享的会话缓存(session cache)来确保跨服务器情景能够有更高的重启会话缓存命中率。同时,确保你会话的过期和会话 ticket 密钥的轮换足够安全,尤其是开启了向前保密的情况下。
你可以从 Let’s Encrypt 得到不限用途的免费证书。如果需要 EV 认证,就得多花一点钱。利用搜索引擎查找并评估所有可选方案。你的访客的数据安全性和完整性值得你花每一分钱!
ECC 加密证书提供了 更强的安全性和更小的证书 — e.g. 一个 256-bit 的 ECC key 安全性相当于一个 3072-bit 的 RSA key。对于像浏览器这样的现代的 TLS 客户端来说,推荐使用 ECDSA 证书,但如果你需要支持缺少 ECDSA 的老旧的客户端 (例如:企业环境下常见的 2008 年以前的操作系统/软件),你可以通过一个 混合证书 来提供后备 RSA 支持。查阅你服务器的文档来了解 RSA+ECDSA 是否被支持。
CRIME 是一种针对 TLS 层压缩的攻击。所有的现代客户端都禁用了 TLS 压缩,但我们仍然建议禁用你服务器上的 TLS 压缩。另一方面,BREACH 是针对 TLS 之上的层次压缩的攻击(例如 HTTP 压缩),所以必须同时在服务器层级以及应用层级来解决 —— 了解更多。
观看 Google I/O 的 HTTPS Everywhere 演讲 (幻灯片)学习将你已有内容安全地迁移到 HTTPS 上的步骤与最佳实践。
每一个未加密的 HTTP 请求都暴露了用户行为有关的信息。时至今日,已经没有所谓“不敏感”的流量了 —— 了解更多。