随着智能手机普及、WIFI 接入常态化,互联网占我们日常生活的比重日渐变大。我们在网上搜索、社交和购物,看似方便快捷,但是有可能你的数据正在被窃听篡改,被黑客组织利用。 造成这种问题的原因是我们平常最为广泛使用的超文本传输协议(HTTP,HyperText Transfer Protolcol)在设计之初并没有考虑安全性问题,导致如今大量数据在网络上明文传输。 HTTPS(HTTP over TLS)是超文本传输安全协议(HyperText Transfer Protocol Secure),是一种通过计算机网络进行安全通信的传输协议,最初由网景公司(Netscape)于 1994 年提出。 HTTPS 在不安全的网络上创建一条安全信道,通过数据加密、数据完整性校验、身份认证等手段,对窃听和中间人攻击进行合理的防护。
如今,全世界都对 HTTPS 抛出了橄榄枝:
HTTPS 是大势所趋,但是 HTTPS 的覆盖率并不广,只有像 BATJ 等大型互联网企业才在最近几年完成了全站 HTTPS 的迁移,究其原因主要是 HTTPS 的实施成本过高:
用户访问延时的增加,给公司产品、服务质量造成不利的影响。从另外一个层面来讲,由于服务端性能骤降,可能需要原本接入集群基础上数倍的机器数量才能支撑当前用户访问。 而且证书的选择、后期运维如私钥存储都具有一定的技术门槛,比如如何在安全性和兼容性层面达到相对平衡,这使得许多公司望而生畏。 本文不涉及 HTTPS 的实现原理以及最佳运维实践,主要谈谈京东金融私有云在 HTTPS 性能提升上的一些经验。 京东金融私有云 HTTPS 卸载服务基于 Nginx 和 Openssl 深度定制,性能优化主要从 延时 和 吞吐率 两个维度考虑。 TLS Record 协议工作在表示层,在传输层和应用层之间提供诸如数据封包,加解密,HMAC 校验等功能,如下图: Nginx 在建立 TLS 连接时会为每个连接分配 Buffer 用于发送原数据(TLS Record Size,默认 16KB),当服务端发送数据时,数据会被切分成 16KB 的多个块,每个块用 MAC 签名,加上协议的元数据以及被加密后的原数据形成一个 TLS Record 结构发送到客户端,在客户端只有当协议栈接收到完整的 TLS Record 时才能够解密验证,才会向应用层提交。 由于 16KB 的包大小以及丢包等因素的影响,相对于 TCP,HTTPS 的 TTFB( Time To First Byte ) 延时较大。 TTFB 是判断网站性能的重要指标,主流浏览器都是边下载边解析渲染的,延时较大最直观的影响就是最终用户在浏览器端看到内容的速度较慢。 当然 TLS Record Size 也不能一味地变小,比如当它等于 MSS 时,变小就会有较大的头部负担,导致整体吞吐量下降。 我们当前使用的是 TLS Record Size动态调整 算法,随着 CWND 从 Initcwnd 增长到 16K,在延时和吞吐量之间达到相对平衡。 通过启用 False Start,客户端可以在 Change Cipher Spec 和 Finished 报文后立即发送应用数据,使得原本需要两次 RTT 的完全握手变更为一次 RTT。 国内南北网络的平均延时是 50ms,这也就意味着每一个地处南方的用户访问地处北方的站点,人均可节省 50ms,效果显著。 根据 RFC7918 文档,只有使用具有前向安全的秘钥交换算法以及足够强度的对称加解密算法时 False Start 才会启动。 需要注意的是,Chrome 浏览器为了解决一些特殊 SSL 服务如 SSL Terminator 硬件设备的不兼容性,要求只有和支持 NPN/ALPN 的服务端通信才会开启 False Start。 NPN 随着 SPDY 被 HTTP/2 代替已被 Chrome 移除,而 ALPN 只在 Openssl-1.0.2 后才开始支持,加之 Openssl 新版本的 Bug 修复以及性能优化,所以如果有条件建议在服务端部署较新版本的 Openssl。 OCSP 设计之初是 CRL(Certificate Revocation List) 的替代品,希望通过在线实时的网络交互检查证书吊销状态,但是这个功能有点鸡肋:
OCSP Stapling 通过服务端对 OCSP 结果的预取并把结果随着证书一起发给客户端,从而绕过客户端的在线验证过程,可以很好地解决上边两个问题。 我们在自己的网站中都应该配置使用 OCSP Stapling,但是需要注意的是 OCSP Stapling 也并非完全能起到检查证书吊销的作用,以至于像 Chrome 浏览器就已经完全不做证书吊销检查了。 HSTS(HTTP Strict Transport Security)通过在 HTTPS Response Header 中携带 Strict-Transport-Security 来告知浏览器:以后请直接通过 HTTPS 访问我,当第二次用户在浏览器端访问 HTTP 站点,浏览器会在内部做 307 重定向,直接通过 HTTPS 访问。如下图: 通过 HSTS 能有效地避免 SSL 剥离攻击,并能减少 2 个 RTT,强烈建议配置使用。但同时也需关注首次访问的中间人攻击,以及准备回滚措施以防 HTTPS 回滚。 常见的会话复用有 Session ID 和 Session Ticket 两种形式,其中 Session ID 是 TLS 协议的标准字段,而 Ticket 是扩展字段,根据相关统计,Ticket 的客户端支持率只有 40% 左右。 通过会话复用,把完全握手变更为简单握手,避免最耗时的秘钥协商阶段,能显著提升性能,如下图,客户端在发起连接时携带上一次完全握手时服务端返回的 SessionID,服务端收到后在内存中查找缓存的会话信息并恢复加密通信。 但是原生 Nginx 只实现了单机版本的会话复用(SSL_SESSION_CACHE 关键字),而当前我们都习惯以集群方式部署 Nginx 来达到高可用,所以我们通过新增 Nginx 模块以及对 Nginx 源码的少量改造,支持分布式会话复用,如下图,无论请求落到哪一台 Nginx 机器,都可以复用已缓存的会话信息。 该 Nginx 模块 (ngx_ssl_session_cache_module) 已经开源,支持 Redis 和 Memcached 两种分布式缓存系统,且对 Openssl 没有任何代码依赖,欢迎使用,详见: https://github.com/hzarch/ngx_ssl_session_cache_module.git 256 位 ECC 秘钥加密强度等同于 3072 位 RSA 秘钥水平且性能更高,而且秘钥更短意味着更少的存储空间,更低的带宽占用,所以对于有条件的企业建议开启 ECC & RSA 双证书支持。 对比 ECDHE_RSA、ECDHE_ECDSA 秘钥交换认证算法所需的 RSA_SIGN、ECDSA_SIGN 算法,以下是我们在普通工作站上通过 OPENSSL SPEED 测试的性能数据,可以明显看到 ECDSA_SIGN 性能提升。 AES-GCM 是目前常用的分组加密算法,缺点是性能低以及移动端耗电量大,所以谷歌在 2014 年推出了一种新的流式加密算法 CHACHA20-POLY1350,在 ARM 平台上性能是 AES-GCM 的 3-4 倍。 Intel 从 Westmere 处理器开始支持一种新的 x86 指令扩展集 AES-NI,AES-NI 能从硬件上加速 AES 的性能,在支持 AES-NI 指令集的主机上实测 AES-GCM 性能是 CHACHA20 的 5 倍左右。 原先我们为权衡兼容性和安全性,所以参考 Mozilla 的推荐 https://wiki.mozilla.org/Security/Server_Side_TLS) 默认采用中档配置,该配置假设客户端不支持 AES-NI,所以 CHACHA20 优先于 AES-GCM,然而随着底层技术的发展,移动端从 ARMV8-A 架构开始逐渐支持 AES 指令集。 像常用的 IPhone 5S,Galaxy Note 4(Exynos),红米 2,锤子 T2,荣耀 5X 等都是基于的 ARMV8 架构,考虑到当前互联网企业的用户都以年轻群体为主,所以我们改变策略优先使用 AES-GCM。 HTTP/2 是 HTTP/1.1 在 1999 年发布后的首次更新,HTTP/2 带来了诸如多路复用、头部压缩、二进制分帧等特性,能大幅提升 Web 性能。 使用时可以让客户端选择或通过 NPN/ALPN 动态协商是采用 HTTP/1.X over TLS 还是 HTTP/2 over TLS,而且后端服务无需修改代码进行适配,具有比较大的灵活性。 但是也需要注意 HTTP/2 并不是万能的解药,使用时需对网站本身的情况做充分评估,需规避诸如为 HTTP/1.X 调优而提出的域名散列等问题。 以上所有的优化都是 软加速 范畴,主要目的是减少 RTT,但是对于无法避免的完全握手,服务端还是会进行大量的加解密运算,以 ECDHE_RSA 为例,像 RSA_Sign 函数在 Intel E5-2650 V2 主机上每秒只能执行 1.2W 次左右,而此时 24 个核已全是满载状态。 CPU 向来都不适合处理大规模的浮点运算,解决这类问题性价比最高的方式无疑是采用硬件加速卡(GPU 就是其中一种),通过把加解密运算转移到加速卡来替换 Openssl 的加解密处理。 加速卡安装在主机的 PCIE 插槽内,受限于主机 PCIE 插槽数量,支持线性扩容,根据加速卡类型不同,像 RSA_Sign 计算性能在单卡状态下都能提升 3-6 倍左右。 利用软优化以及硬件加速卡,基本能满足大部分的业务场景,但这却不是最优解,我们发现:
在老旧的 Intel E5-2620 主机测试 Openssl-1.0.2 单核 ECDH 性能达到 8040,4 倍于 Openssl-1.0.1u,24 核全开时性能达到 9.7W,在 E5-2650 V2 上,极限性能更是达到 17.5W,远高于加速卡单卡的 5-8W。 正是由于这种差异性,我们提出算法分离的架构,希望充分利用硬件性能。 如上图,通过这种架构我们把接入集群从 CPU 密集型 转换成 IO 密集型,具体的算法运算,私钥存储等都在专有集群完成,极大地增强了接入集群的可扩展性。 另外通过这种架构我们不仅可以充分利用闲置的计算资源,也可以最优化 HTTPS 卸载服务的吞吐率,而且对于计算集群的增删改,我们支持在 Web 管控端上批量修改,卸载服务会实时拉取并应用修改,此外再辅以计算集群的整体监控,极大地简化了运维复杂度。 以上优化总结起来就是面向延时和吞吐率的优化,以下是我们在测试环境测试的一组单机性能数据(Intel E5-2650 V2),仅供参考。 由于无法优化浏览器端代码,当前延时只能优化到一个 RTT,若客户端私有,可参考 TLS V1.3 开发 0-RTT 协议。 HTTPS 是个系统性工程,而性能优化只是其中一块,还需要解决诸如证书、运维、网络等问题,但是好消息是,随着国内一些大企业实施 HTTPS 已经有一些最佳实践被探索,以及诸如 Let's Encrypt 等免费 DV 证书推出,HTTPS 的成本正在逐渐降低,所以在此呼吁各企业尽快上线 HTTPS,保障网站的信息数据安全。 吴建苗,京东金融研发工程师,关注负载均衡,消息队列,网络等方向。 |
|