查看原文
其他

全站HTTPS没你想象的那么简单,电商网站兼顾安全与性能的踩坑小结!

2017-09-11 朱羿全 51CTO技术栈

众所周知,数据 HTTP 明文传输过程中,会遇到如劫持、篡改、监听、窃取等一系列问题,解决这一问题的方法就是做 HTTPS 改造。


HTTPS 的作用是在会话层、表示层引入 TLS/SSL 握手协议,通过数据加密、解密方式,来应对数据明文传输过程中遇到的问题,保障数据的完整性、一致性,为用户带来更安全的网络体验、更好的隐私保护。


然而,HTTPS 增加了 TLS/SSL 握手环节,再加上应用数据传输需要经过对称加密,对性能提出了更大的挑战。


作为一个好的架构,一定要均衡安全和性能两方面,如果让天秤向任何一方倾斜过多,都会影响最终的用户体验。


因此,为了兼顾安全与性能,苏宁的全站 HTTPS 改造从 2015 年底开始进行,历时一年多时间,主要做了系统 HTTPS 改造、HTTPS 性能优化和 HTTPS 灰度上线这三方面工作,让用户在 HTTPS 下访问能够获得极致体验成为了可能。

全站 HTTPS 方案概述

苏宁易购从 2015 年开始规划做 HTTPS 相关的事情,当时可借鉴的资料非常少,电商类网站相关的 HTTPS 改造的详尽案例更是难求。


如下图,是苏宁易购全站的 HTTPS 方案:

如图中所示,整个方案分三步构建,分别是系统改造、性能优化和灰度上线:

  • 系统改造。原有系统想要支持 HTTPS,必须进行改造,首先要建立 HTTPS 接入层,也就是开通 443 端口,让所有的应用系统支持 HTTPS 访问。

    在此基础上做页面资源替换,解决当一个 HTTPS 页面出现 HTTP 请求时就会出现错误的问题。做完这两件事,CDN 上证书的处理、HTTPS 测试方案等问题也就迎刃而解。

  • 性能优化。做系统改造,增加两次 TLS 握手,必然会对性能造成一定的开销和损失,如何去弥补性能的损失,达到性能和安全兼顾呢?性能优化部分包含若干优化点,下文会详细展开。

  • 灰度上线。这部分是时间花费最多的,HTTPS 一步步上线的过程中,踩坑最多,其中部分是前面没有发现的问题。

    这证明不能一次性将整个全站、全地区、全用户一次性堆成 HTTPS,可以根据流量所处的运营商和城市及用户级别去做灰度上线。

HTTPS 方案之系统改造篇

01

HTTPS 接入层定义

系统改造的头等大事是开通 443 端口,成熟的网络系统会包含 CDN、硬件负载均衡、应用防火墙、Web 服务器、应用服务器,最后到数据层。难道整个链路都要做 HTTPS?在每层都增加 SSL 握手消耗吗?答案是否定的。


所以,应该尽早完成 SSL 握手,做 SSL 过程中首要考虑的是 HTTPS 接入层的定位。


如下图,是苏宁易购架构中 HTTPS 接入层的位置:

如图中所示,我们把 HTTPS 接入层放在 CDN 和应用系统之间,采用四层+七层负载均衡的架构。


四层负载并不处理 HTTPS 卸载,它的主要职责是做 TCP 的分发。在七层负载完成整个 SSL 握手,而后面应用系统走 80 端口,这样就相当于完成了 HTTPS 整个卸载的过程。


这样做的好处,一方面,系统应用层面不需要为 HTTPS 做任何调整;另一方面,将来所有 HTTPS 的调度、优化和配置都可以在接入层完成。

02

页面资源替换

第一步,理解 Mixed Content


对于一个页面而言,请求页面的请求是用 HTTPS 加载,一旦内部页面元素有 HTTP 的性质,这时 RFC 标准里就会出现一个错误,叫 Mixed Content(混淆错误)。


所以,如果要加载一个安全的 HTTPS 页面,就不应该在其中混淆 HTTP 请求。


第二步,// 替换 http://


用 // 替换 http://,这样就可以让页面所有的元素做一个适配,去遵循原来的请求。


第三步,x-request-url 的定义和使用


当然,我们在//替换过程中也遇到了一些坑。举个例子,下图是苏宁易购单点登录系统交互的过程:

如图中所示,当用户 authID 失效,发起请求 https://xxx.suning.com/authStatus 鉴权,接入层会对所有请求做卸载,地址就会变成 HTTP。


进入业务系统做鉴权的话,Reponse 302 就会跳转到单点登录系统。这时会将第二步的页面记录为原始页面,返回到用户端,用户去请求单点登录系统,单点登录系统完成鉴权以后,再回跳时,是 HTTP 地址,最终导致用户端 MixContent。


因此,我们引入 x-request-url 解决问题,如下图:

所有原始请求协议都记录在 x-request-url 中,如果业务系统鉴权,一定要遵循 x-request-url 记录的协议,就可应对回跳导致的用户端 Mix Content 问题。

03

App 原生无法识别//的问题

出现浏览器可以识别 //,但 App 原生无法识别 // 的原因很简单,因为浏览器本身做了适配。


当时,苏宁服务端有一个系统,专门提供一个接口,向各个端提供图片。做完 HTTPS 改造之后,PC 端和客户端都没有问题。但是第二天,很多用户突然就不能加载图片,原因是请求在 APP 原生情况下没法识别 //。


这里的解决方法,只能是客户端开发人员做适配,下图是 App 无法识别//的一个例子:

04

如何处理商用 CDN 上的证书和私钥?

CPN 证书的处理是大多数小型互联网企业都会遇到的问题。因为这些小企业不像阿里、京东可自建 CDN,苏宁也是一样。


苏宁的 CDN 由自建和商用两种组成,一旦使用商用 CDN,就会面临 HTTPS 如何过去的问题。


企业只要将私钥给到第三方或厂商之后,在所有厂商的 CDN 服务器都没办法控制。当有黑客攻击完厂商服务器后,加密已没任何意义,因为私钥已经泄露。


如下图,业界比较公认的应对方式分别是:双证书的策略、四层加速和 Keyless 解决方案。

  • 双证书的策略。它的思想很简单,相当于用户到 CDN 端,提供的是 CDN 的证书,做加解密。从 CDN 到应用服务器端用的是应用自有的证书来做加解密。

    这样的方式,可以保证应用端的密钥不用提供给 CDN 厂商,但根本的问题还是没有解决,那就是 CDN 厂商的证书仍然有泄露的可能。如果泄露了,用户端还是会受到影响。

  • 四层加速。很多 CDN 厂商都有能力提供 TCP 加速,做动态、还原和择优等。CDN 厂商只做四层模式和 TCP 代理,不考虑请求缓存。

    这样就没必要将证书暴露给 CDN 厂商,这种方式适用于动态回源请求,比如加入购物车、提交订单、登录等。

  • Keyless 解决方案。适用于金融,提供一台实时计算的 Key Server 。

当 CDN 要用到私钥时,通过加密通道将必要的参数传给 Key Server,由 Key Server 算出结果并返回即可。

05

HTTPS 测试策略

当引入一个新的协议,如何进行测试呢?主要步骤,如下图:

  • 源码扫描。当开发人员完成资源替换后,利用 Jenkins 遍历代码库,shell 脚本扫描出 HTTP 链接。

  • 对页面爬虫扫描。我们会写一些爬虫脚本,对测试环境的链接进行扫描。

  • 测试环境验证。自动化测试固然好,但是主要核心流程还是需要手动覆盖一遍,防止 HTTPS 对页面加载出现未知影响。

    如有些页面是用 HTTPS 去访问,可能这个系统还不支持 HTTPS,必须要手动验证。

  • 线上预发和引流测试。HTTPS 的改造版本发到线上对用户来讲是没有影响的,因为用户使用的还是 HTTP 流量。

    可以选择线上预发的方式,预发验证完毕后,通过 301 的方式,将用户的流量从 HTTP 切到 HTTPS,这个后面讲灰度时还会深入讲解。


另外,我们还引入了引流测试系统:

它的思路很简单,根据域名、用户请求做捕获,将所有捕获流量放到 Copy Server 中去扩大,放大若干倍,然后通过 Sender 再发送回到系统中。


这样的方式,可以通过用户的真实流量,来验证 HTTPS 的功能性和性能影响有多大。

HTTPS 方案之性能优化篇

谈如何优化 HTTPS 的性能之前,我们先来看看整个 TLS 握手流程,如下图:

如图中所示,一个握手过程最坏的情况下,要分为八个步骤:

  • 发送 Syn 包到 Web 客户端,收到并确认后,同时发送 SynAck 到服务器,这时还是一个 HTTP 的请求。

  • HTTP 转换 HTTPS,需要做一次 302 或者 301 跳转。

  • 用户再次发送 HTTPS 请求,做一次 TCP 握手。

  • 做 TLS 完全握手第一阶段,Clienthello 到 Server hello。

  • 当证书首次到客户端,客户端需要走验证流程,做 CA 域名解析。

  • 第二次,TLS 握手。

  • 在线证书合法性校验的过程。

  • TLS 完全握手第二阶段,底部灰色部分才是真正的数据通讯。


苏宁易购的全站 HTTPS 方案在性能优化方面做了很多事情,如 HSTS、Session resume、Ocsp stapling 的合理使用,如客户端 HTTPS 性能、HttpDNS 解决 DNS 攻击劫持等优化。

01

HSTS 的合理使用

Web 安全协议 HSTS 的作用是强制客户端(如浏览器)使用 HTTPS 与服务器创建连接。


优点是减少 HTTP 做 302 跳转的开销。302 跳转不仅暴露了用户的访问站点,也很容易被中间者劫持(降级劫持、中间人攻击),最重要是降低了访问速度(影响性能)。


缺点是 HSTS 在 max-age 过期时间内,在客户端是强制 HTTPS 的,服务端无法控制。


因此,当需要降级时,HTTPS 无法及时切换到 HTTP。当然你也可以通过手动动态去配置 max-age 的值,这样可以通过将 max-age 设置为 0 来达到降级效果。


还有 HSTS 是严格的 HTTPS,一旦网络证书错误时,网页将直接无法访问(用户无法选择忽视)。

02

Session resume 的合理使用

当用户端和客户端、客户端和服务端完成第一次 TLS 握手之后,第二次数据传输还需要 TLS 握手吗?


这里可以采用 Session 复用的方式。Session resume(会话复用),是 RFC 标准中早就定好的一个机制,HTTPS 最初发布时就已经涉及其中。


Session 复用有 Session ID 和 Session tickets 两种方式,下图是实现流程:

  • Session ID。使用 clienthello 中的 session ID 查询服务端的 session cache,如果服务端有对应的缓存,则直接使用已有的 session 信息提前完成握手,称为简化握手。

    Session ID 是 TLS 协议的标准字段,市面上的浏览器全部都支持 Session ID。需要注意的是,单机多进程间共享 ssl session 对集群环境是没有意义的。

    因此,在这里需要实现多机共享 Session ID。可以放在 redis 中,nginx 提供了专门处理 Session ID 的模块 ssl_session_fetch_by_lua_block。

  • Session tickets。Session tickets 是会话 ID 的一种补充,server 将session 信息加密成 ticket 发送给浏览器,浏览器在后续握手请求时会发送 ticket,server 端如果能成功解密和处理 ticket,就能完成简化握手。

    显然,session ticket 的优点是不需要服务端消耗大量资源来存储 session 内容。但是 session ticket 只是 TLS 协议的一个扩展特性,目前的支持率不是很广泛,只有 60% 左右。

    还需要维护一个全局的 KEY 来加解密,需要考虑 KEY 的安全性和部署效率。

03

Ocsp stapling 的合理使用

Ocsp 全称在线证书状态检查协议 (rfc6960),用来向 CA 站点查询证书状态,比如证书是否被撤销,是否已经过期等。


通常情况下,浏览器使用 OCSP 协议发起查询请求,CA 返回证书状态内容,然后浏览器接受证书是否可信的状态。


如下图,是 Ocsp 实现流程:

这个过程非常消耗时间,因为 CA 站点有可能在国外,导致网络不稳定,RTT 也比较大。那有没有办法不直接向 CA 站点请求 OCSP 内容呢?


ocsp stapling 就能实现这个功能。ocspstapling 的原理简单来说是服务端代替客户端完成 CA 校验证书的过程,节省用户端的时间开销。


就是当浏览器发起 clienthello 时会携带一个 certificate status request 的扩展,服务端看到这个扩展后将 OCSP 内容直接返回给浏览器,完成证书状态检查。


由于浏览器不需要直接向 CA 站点查询证书状态,这个功能对访问速度的提升非常明显。

HTTPS 方案之灰度上线篇

灰度上线可遵循灰度、降级和开闭三大原则。灰度原则是指整个上线过程要按区域、版本、用户等级来进行灰度,通过灰度收集上来的用户数据来决定整个计划的进行。


降级原则保证每一步的操作都是可逆可回滚的,即对扩展开放,对修改关闭,这是可复用设计的基石。

01

HTTPS 开关控制

HTTPS 开关控制方面,苏宁主要建设内容管理、CDN、客户端三大开关:

  • 内容管理开关。内容管理开关的作用是保证所有运营维护的链接都可以被替换。

  • CDN 开关。每个页面,从 HTTP 到 HTTPS 都需要做 301 跳转,这些跳转都配置在 CDN 中。

  • 客户端开关。就是移动加速 SDK 的开关。

02

上线过程中遇到的新问题

做完开关控制,在正式上线的过程中,又遇到了一些新问题如:Referrer、DNS 劫持、HTTPS 性能监控等。


Referrer


目前大部分浏览器,在发生协议降级时默认不发送 Referrer 信息,最典型的场景就是从 HTTPS 页面点链接跳到 HTTP 网站时,浏览器并不会在请求头中带上 Referer 字段。当 Referrer 带不过去,对大数据的影响非常大,因为没办法追溯流量来源。


针对现代的浏览器,这个问题可以通过给页面加上下面这个 meta 标签来解决:<meta name="referrer" content="always" />


DNS 劫持


DNS 劫持是指非法破坏域名的解析过程导致请求被解析到一个错误节点以达到某些恶意目的。当我们使用 HTTP时,DNS 异常可能还不会影响请求的功能性,但 HTTPS 因为非法节点没有证书和私钥,肯定是无法响应了。


苏宁的做法的是通过一些波测监控 DNS 的正常,如下图,我们监测到苏宁中华特色馆在某个地区有大量 DNS 解析异常。

出现 DNS 劫持,对用户影响很大,一旦出现一次页面打不开,用户就会认为这个页面有问题,不会在进行二次访问。


如下图,是苏宁易购河北地区出现的问题:

如图中所示,页面整个框架都在,但就是没有图片,最终确定是由 DNS 劫持导致的。


这里的应对方法就是要建立完整的风控体系,在全国各地建设波测节点,做整个请求图片、页面的记录,并保存,如下图:

当时,河北地区用户发出请求后,TCP 没有办法建立连接,使用 SSL 无法握手。原因是 DNS 劫持,被映射到非法的错误节点上了。


应对方法还是我刚才说的降级手段,通过 IP 判断是河北移动的用户就对 HTTPS 进行降级成 HTTP,其他地方还继续使用 HTTPS 策略。待当地运营商解决问题之后,再进行恢复。


HTTPS 性能监控


如下图,是苏宁易购移动端的监控页面:

HTTPS 灰度最重要的一个是做好监控,必须要有一个监控覆盖,要做好灰度,每一步上线时都要分析一下业务、性能、站内站外投放,CPS 等数据。


一切数据分析都正常之后,再逐步扩大区域,按 APP 的版本和用户级别进行部署。

HTTPS 未来展望篇

这里分享一个基于 UDP 的低时延的互联网传输层协议:QUIC(Quick UDP Internet Connection)。


TCP/IP 协议族是互联网的基础,这个 UDP 协议由谷歌提出,其用意是替代 TCP 协议。


这两种协议,UDP 更为轻量,错误校验也要少得多,但可靠性方面要弱于 TCP。目前,针对 QUIC 协议,国外一些公司在试用阶段,强调的是既保证安全,又能保证握手不会对原来的传输造成影响,这也许是未来的发展方向。

微信后台回复关键词“HTTPS”,即可下载完整PDF资料

作者:朱羿全

编辑:王雪燕、陶家龙、孙淑娟

来源:以上内容由编辑王雪燕根据朱羿全老师在 WOTA2017 “电商大促背后的技术挑战”专场的演讲内容整理。

投稿:有投稿、寻求报道意向技术人请联络 editor@51cto.com


朱羿全

苏宁云商 IT 总部架构师

先后参与了全景应用性能监控平台搭建、移动端性能优化与提升、移动端统一接入层建设等工作,主导了苏宁易购全站 HTTPS 上线和优化工作。专注于应用层网络性能优化,在 HTTPS、HTTP/2 等领域拥有丰富的经验,目标是通过优化,以保证复杂网络环境下,通信的快速、稳定和安全。

精彩文章推荐:

IT从业17年,谈谈技术人创业的A+人才招聘观

3亿会员、4亿商品,深度学习在大型电商商品推荐的应用实践!

成为技术大牛的秘诀都在8月的这十篇热门文章!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存