iOS 电商网站HTTPS实践之路——性能优化篇

通过分析TLS握手过程的细节我们会发现HTTPS比HTTP会增加多个RTT网络传输时间,既增加了服务端开销,又拖慢了客户端响应时间。因此,性能优化是必不可少的工作。很多文章都集中在服务端的性能优化上,但对于电商行业而言,大部分的用户流量源于应用程序,因此客户端的性能优化配合服务端才能使收益最大化。

1.HTTPS带来的负担

1.1增加的传输延时
1.2服务端额外开销

2.服务端性能优化

2.1 HSTS的合理使用
2.2会话恢复的合理使用
2.3 Ocs Stapling的合理使用
2.4 TLS协议的合理配置
2.5 False Start的合理使用
2.6 SNI功能的合理使用
2.7 HTTP 2.0的合理使用
2.8 SSL硬件加速卡合理使用

3.客户端性能优化

3.1移动端HTTP2加速代理
3.2 HttpsDns解决DNS攻击劫持

1.HTTPS带来的负担凡事都有两面性。

1.1 增加的传输延时使用HTTPS传输增加的开销不仅仅是两次TLS握手的过程。优化性能首先要知己知彼。了解性能损耗在哪里,才能有针对性的进行部署。对于用户来说,使用HTTP请求,首次请求时只要和服务端TCP三次握手建立连接,便可以开始应用数据传输了。
1.用户习惯于使用HTTP请求你的网站。要保护用户的安全,首先要让用户强制三百○一分之三百○二到HTTPS。这次跳转至少增加1个RTT的延时;
2. 302跳转后要再次TCP建连,增加1个RTT的延时;
3. 开始两阶段TLS握手,细节如下图所示,增加至少两个人RTT的延时。这里写图片描述- Client Hello:客户端开始新的握手,并将自身支持的功能提供给服务端; - Server Hello:服务端选择连接参数; - Certificate :服务端发送证书链; - ServerKeyExchange :服务端发送公钥(公钥)等生成主密钥(预主秘密Hey hey)的额外信息给客户端; - ServerHelloDone:服务端通知完成协商过程; - ClientKeyExchange:客户端发送加密后的主密钥给服务端- [ChangeChiperSpec]:客户端如果要切换加密方式通知服务端-完成:客户端完成-[ChangeChiperSpec]:服务端如果要切换加密方式通知客户端
-完成:服务端完成
4.另外客户端如果第一次获取服务端的证书链信息,还需要通过Oscp来验证证书的吊销状态,又需要至少1个RTT延时。
5.最终,开始应用层数据的传输。
1.2服务端额外开销TLS握手过程中密钥交换和加密对CPU都会产生额外的计算开销。选择不同的算法(身份验证算法,密钥交换算法,加密算法)开销不同。比如,2048位RSA作为密钥交换算法对CPU压力就会很大,而ECDHE_RSA(椭圆曲线密钥交换)开销就小的多,RSA可以仍保留用于身份验证。当然,不管选择多优化的算法,开销是避免不了的,如下图所示。这里写图片描述

2.服务端性能优化服务端性能优化,主要体现在Web服务器配置的优化,我们以Ngnix 1.11 .0版本为例。当然你也可以选择Apache,H2O等。

2.1 HSTS的合理使用HSTS(HTTP严格传输Se HTTP严格传输安全协议)表明网站已经实现了TLS,要求浏览器对用户明文访问的Url重写成HTTPS,避免了始终强制302重定向的延时开销。
HSTS的实现原理是:当浏览器第一次HTTP请求服务器时,返回的响应头中增加Strict-Transport-Security,告诉浏览器在指定的时间内,这个网站必须通过HTTPS协议来访问。也就是对于这个网站的HTTP地址,浏览器需要现在本地替换为HTTPS之后再发送请求。
其配置如下所示。max-age表明HSTS在浏览器中的缓存时间,includeSubdomainscam参数指定应该在所有子域上启用HSTS,preload参数表示预加载,稍后会具体解释。
在CanIUse上我们可以查询HSTS协议的浏览器支持度:
这里写图片描述
在使用HSTS的过程中仍有一些值得注意的问题:
1. HSTS将全部的证书错误视为致命的。因此,一旦主域使用HSTS,浏览器将放弃对域名所有无效证书站点的连接。
2. 首次访问仍然使用HTTP,然后才能激活HSTS。无法保障首次访问的安全性如何解决?可以通过preloading预加载的方式,与浏览器厂商约定好一份支持HSTS的网站清单来缓解。目前Google已经提供了在线注册服务https://hstspreload.appspot.com/
3. 如何撤销HSTS?通过Strict-Transport-Security: max-age=0将缓存设置为0可以撤销HSTS。但是只有当浏览器再次访问网站并且得到响应更新配置时才能生效。

2.2 会话恢复的合理使用
会话恢复机制是指在一次完整协商的连接断开时,客户端和服务端会将会话的安全参数保存一段时间。后续的连接,双方使用简单握手恢复之前协商的会话。大大减少了TLS握手的开销。
会话恢复的方案可以分为两种:会话ID(Session ID)和会话票证(Session Ticket)。会话ID通过服务端为会话指定唯一的标识,并缓存会话状态。在第一次完整协商的过程中,ServerHello消息中将会话ID发回客户端。希望恢复会话的客户端在下一次握手中将会话ID放入ClientHello,服务端认可后接着使用之前协商的主密钥进行加密。而会话票证将所有会话状态保持在客户端(类似于HTTP Cookie)。
1. 配置会话票证较为简单:
注意集群情况下key值保持一致。另外注意使用会话票证前需要开启支持前向性加密支持的密钥套件。
2. 配置会话ID需要注意,会话状态是保存在服务器上的,集群状态下如何保证会话ID的命中率?最简单的方式是负载的轮询策略使用IP_HASH,保证同一客户端总是被分发到集群中的相同节点,但这样未免不够灵活。因此需要采用分布式缓存的方式,将会话状态存储在集群共享的redis中。
如何操作Nginx中的TLS会话信息,可以参考openresty中的ssl_session_fetch_by_lua_block 模块。

2.3 Ocsp stapling的合理使用
OCSP(Online Certificate Status Protocol, 在线证书状态协议)用于查询证书的吊销信息。OCSP实时查询会增加客户端的性能开销。因此,可以考虑通过OCSP stapling的方案来解决:OCSP stapling是一种允许在TLS握手中包含吊销信息的协议功能,启用OCSP stapling后,服务端可以代替客户端完成证书吊销状态的检测,并将全部信息在握手过程中返回给客户端。增加的握手信息大小在1KB以内,但省去了用户代理独立验证吊销状态的时间。
启用OCSP stapling的方式有很多种,比如在线校验。此方式需要支持服务器能够主动访问证书校验服务器才能生效,并且在每次重启nginx的时候会主动请求一次,如果网络不通会导致nginx启动缓慢。

启用OCSP stapling

#启动 OCSP响应验证,OCSP信息响应适用的证书
2.4 TLS协议的合理配置首先要指定TLS协议的版本,不安全的SSL2和SSL3要废弃掉ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 1 其次,建议启用ssl _ prefer _ server_ciphers,用来告诉Nginx在TLS握手时启用服务器算法优先,由服务器选择适配算法而不是客户端:ssl _ prefer _ server_ciphers on 1 然后,选择最优的加密套件以及优先顺序,具体可参考的Mozilla的https://wiki.mozilla.org/Security/Server_Side_TLS

证书吊销列表

2.5 False Start的合理使用
TLS False Start是指客户端在发送ChangeCipherSpec Finished 同时发送应用数据(如HTTP请求),服务端在 TLS 握手完成时直接返回应用数据(如HTTP响应)。这样,应用数据的发送实际上并未等到握手全部完成,故谓之False Start。
这里写图片描述
要实现False Start,服务端必须满足两个条件:
1. 服务端必须支持NPN(Next protocol negotiation, ALPN的前身)或者ALPN(Application layer protocol negotiation, 应用层协议协商);
2. 服务端必须采用支持前向加密的算法。
补充说明下什么是前向加密(perfect forward secrecy)。前向加密要求一个密钥只能访问由它所保护的数据;用来产生密钥的元素一次一换,不能再产生其他的密钥;一个密钥被破解,并不影响其他密钥的安全性。

2.6 SNI功能的合理使用
SNI(Server Name Indicate)允许客户端在发起SSL握手请求时(ClientHello阶段),就提交请求的Host信息,使得服务器能够切换到正确的域并返回相应的证书。通过这种方式解决了一个IP(虚拟机)部署多个域名服务的问题。
Nginx支持SNI的方式并自动开启。当遇到不支持这一特性的客户端用户时,通常情况下,Nginx会返回默认站点的服务器证书。比如下面的情况下,不支持SNI的客户端,Nginx返回serversuning.pem。这样证书是否能正确匹配是无法保障的,会带来不必要的麻烦和困扰。因此,移动端开发都应该要求启用SNI扩展。
2.7 HTTP 2.0的合理使用
HTTP 2笔者在《 HTTP 2.0 原理详细分析》和《 Nginx实现HTTP/2——原理、实践与数据分析》中都有详细地介绍,这里就不再展开。需要提示下,Nginx在1.9.x版本就开始尝试支持http2协议,但每个版本都会有bugfix,仍需要谨慎开启,具体可参考Nginx版本更新日志。

扫描二维码关注公众号,回复: 930347 查看本文章

2.8 SSL硬件加速卡合理使用
可以通过SSL硬件加速卡设备来代替CPU进行TLS握手过程中的运算。推荐的有Cavium的加速卡,Cavium引擎可以集成到Nginx模块中,支持物理机和虚拟机环境。同时,虚拟机环境下的测试效果要比物理机好。建议开启Nginx异步请求Cavium引擎模式,更有效提高使用率。
下面是我们压测的CPU到20%情况下,使用TLS 1.2协议、加密套件采用ECDHE-RSA-AES128-SHA256 、HTTPS 短连接的各种环境性能数据,可见使用Cavium,物理机性能提升比:325%,虚拟机性能提升比:588%。

环境 流量类型 TPS 延迟(s)
虚拟机 HTTPS 172 0.066
虚拟机 + Cavium加速卡 HTTPS 1012 0.066
物理机 HTTPS 832 0.066
物理机 + Cavium加速卡 HTTPS 2708 0.059
另外,是否使用硬件加速见仁见智了,其在性能提升上肯定是有效果的,但由于设备价格高昂,很难大规模化,对于大部分互联网公司是一件奢侈品。借用Facebook关于硬件加速的说法:
“我们发现当前基于软件的TLS实现在普通CPU上已经运行的足够快,无需借助专门的加密硬件就能够处理大量的HTTPS请求。我们使用运行于普通硬件上的软件提供全部HTTPS服务。”

3. 客户端性能优化

App中使用HTTPS请求,建议设计客户端的代理层SDK。代理层的主要目的包括两点:(1)统一以HTTP 2协议向服务端转发请求;(2)调用服务端HttpDns接口,获取准确的地址解析信息。

3.1 移动端HTTP2加速代理
比如Android使用组件OkHttp 3,IOS使用组件NSURLSession,都可以支持HTTP 2.0协议。我也曾翻译介绍过《OkHttp, 安卓和Java应用的HTTP&HTTP2.0客户端》。深入到具体代码开发和使用层面不在本文中展开。只有当客户端和服务端都采用HTTP 2.0进行通信,才能达到加速的效果。通过数据也能印证HTTP 2.0的效果。
这里写图片描述

3.2 HttpsDns解决DNS攻击劫持
Dns劫持通过篡改用户的解析指向,将用户的流量导向第三方,以实现恶性盈利的目的。另外还有一些运营商为了避免网间结算费用,会在内网做站点镜像,再通过Dns劫持的方式,使用户直接访问镜像。
这里写图片描述
当全站实现HTTPS后,由于缺乏证书和私钥等必要信息,能够保证他人Dns劫持用户后无法达到非法目的,但同时也无法正常响应用户的请求。这就是一把双刃剑,因为普通用户只会认为是你的网站加载不出来。
这里写图片描述
所以,全站HTTPS只能避免Dns劫持带来的损失,解决Dns劫持问题还需要另觅良法。从根本上而言Dns劫持的原因是我们无法控制本地的LocalDNS不被黑(毕竟是运营商的东西你懂的),那么有没有可能绕开运营商解析?PC端我们肯定是做不到的,而移动端App我们可以使用HttpsDns的方案。
HttpsDns方案:用Https协议(IP代替域名)向HttpDns集群(权威DNS)的443端口进行请求,代替传统的DNS协议向DNS服务器的53端口进行请求。也就是使用Https协议去进行dns解析请求,将服务器返回的解析结果,也就是域名对应的服务器ip获得,直接向该ip发起对应的api服务请求,代替使用域名。备选情况下(HttpsDns解析失败),再走传统的LocalDNS解析方式。
这里写图片描述
HttpsDns的方案优势在于:
1. 防止了LocalDNS劫持问题
2. 平均访问延迟下降,由于后续请求直接通过IP访问,省去了域名解析时间。并且可以通过一些算法计算出最优性能的服务端IP(Ping延时最小),缓存在客户端本地地址库;
3. 用户连接失败率下降
目前提供HttpDns服务端能力的厂商有中网、dnspod等,基本上是以约定接口的形式供客户端来调用,返回解析结果。比如:
这里写图片描述
客户端的实现并没有想象的简单,用ip替换域名访问,要考虑很多问题,比如:
1. Https场景下ip直连出现的证书校验问题
2. 代理场景下的HttpDns问题
3. ip访问的时候Cookie的问题
在这里我们不再展开,有兴趣可以参考:
《Android 使用OkHttp支持HttpDNS》 http://blog.csdn.net/sbsujjbcy/article/details/50532797
《Android OkHttp实现HttpDns的最佳实践(非拦截器)》 http://blog.csdn.net/sbsujjbcy/article/details/51612832
CNSRE/HTTPDNSLib https://github.com/CNSRE/HTTPDNSLib

以上,针对TLS层的性能优化就已经完结了。然而,这就结束了吗?性能提升就到此为止了吗?当然不是。一方面,我们还应该关注与最大限制地去提升TCP层的性能,来配合TLS的优化。包括初始拥塞窗口调优、防止空闲时慢启动、keep-alive等;
另一方面,关注更新的技术成果和动态,比如追求0RTT损耗的TLS 1.3、QUIC协议等

君凯商联网-iOS-字唐名僧

猜你喜欢

转载自blog.csdn.net/u010960265/article/details/80347214