电商网站HTTPS实践之路——系统改造篇

Posted 皖南笑笑生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了电商网站HTTPS实践之路——系统改造篇相关的知识,希望对你有一定的参考价值。

首先是要让系统支持HTTPS。 需要有接入层来统一处理TLS握手。页面资源的替换也存在一些坑。对于不同的域证书选择上也要注意,最好的方式是提前整理好域列表绑定成一张支持多域名和泛域名的证书。大多数互联网公司的CDN资源都是租用的,CDN上证书如何来处理。最后,HTTPS的测试策略如何实施,来保证页面不会出现Mix content阻塞和net: ERR_INSECURE_RESPONSE错误。

1. HTTPS接入层的设计

开通服务端的443端口,用户发起HTTPS请求服务端才能正常响应。然而,一般的电商网站可不仅仅只是一台Tomcat,都会考虑性能和各种架构优化。基本上会是:客户端 -> CDN(静态缓存+动态加速) -> 四层负载均衡(F5/Ctrix/LVS) -> 七层负载均衡(Niginx)-> Web服务器(Apache) -> 应用服务器(Tomcat)-> 数据层。难道每一层都需要开启443端口进行TLS握手嘛?我们知道TLS握手过程会徒增至少两次RTT时间,这样的性能损耗我们是不能接受的。
因此,需要尽早完成TLS握手,对于后端仍使用HTTP通信。包括Facebook淘宝等都提到过统一接入层的架构来“卸载”TLS协议。如下图所示,我们的接入层设计在CDN之后,应用服务器之前,是内外网之间的屏障。对于静态资源,命中CDN缓存后直接得到响应;对于动态回源请求,在HTTPS接入层完成握手过程,upstream到系统走80端口。


通过HTTPS接入层的建设,
1. 性能得到提升。一方面,传输的RTT减少了,另一方面,应用系统本身不存在握手来消耗cpu;
2. 实现了流量的统一调度。未来优化、升级、管控流量都集中在HTTPS接入层上。

2. 页面资源的替换

2.1 令人讨厌的Mix Content

混淆内容(Mix Content),简单来说是指HTTPS页面中混淆了HTTP请求。
通常当用户代理通过一个安全信道(如HTTPS)从一个特定站点加载一个资源(如Web页面)时,用户代理可以获得关于该资源的用户安全和隐私状态的三种判断:认证性(authenticated)、加密性(encrypted)及数据完整性(data integrity)。这些判断对于防止资源内容被篡改或窃听,抵御中间人攻击非常重要。但如果这些经过认证和加密的资源再通过一个非安全的信道(如HTTP)请求其他的子资源(如脚本、图片等),该资源的安全性就不再能够得到保证,从而处在一个混合状态,而事实上这一情况非常普遍。
因此,W3C颁布了针对Mix Content的安全标准,描述了用户代理、浏览器在处理加密和认证的文档时,如何禁止(disallow)对经过非加密方式或非授权连接所加载的子资源进行渲染或执行。
浏览器遵循Mix Content标准,并在控制台打印出报错信息:

Mixed Content: The page at 'https://product.suning.com/0000000000/129564647.html?srcpoint=index3_homepage1_32618213038_prod01' was loaded over HTTPS, 
but requested an insecure image 'http://image.suning.cn/uimg/PCMS/prmtExposition/149310522123830711.png'. 
This content should also be served over HTTPS.

Mix Content又可以分为两类:
Blockable:浏览器严格禁止加载这类资源。比如javascript、CSS
Optionally-blockable:可商榷的混淆内容,现代浏览器默认会加载这类资源,同时会在控制台打印警告信息。比如<img><video><audio><source>标签加载的内容。
值得注意的是,IE 8及以下并不属于现代浏览器范畴,不区分BlockableOptionally-blockable,都会弹框警告。

2.2 解决Mix Content

在你确定全站都支持HTTPS,并且全站替换为HTTPS访问前(当然这是一个相对漫长,需要过渡的过程)。解决Mix Content最好的方案是使用相对协议。对于同时支持HTTPS和HTTP的资源,引用的时候要把引用资源的URL里的协议头去掉,浏览器会自动根据当前场景是HTTPS还是HTTP来给资源URL补上协议头的,可以达到无缝切换。
比如:

<a href="//product.suning.com/0000000000/129564647.html?srcpoint=index3_homepage1_32618213038_prod01" >

简而言之,就是将URL的协议(http、https)去掉,只保留//及后面的内容。这样,在访问https的网站时,浏览器会通过https加载请求,在访问http的网站时,浏览器会通过http加载请求。
相对协议同样适用于css样式中,比如:

.imgview .mask-rright:0;cursor:url(images/next.cur),pointer;cursor:url(//res.suning.cn/project/pdsWeb/csspc/images/next.cur),pointer\\0    

另外,在使用相对协议的时候存在一个坑。App原生接口并不能默认适配相对协议,比如,

OkHttp.Request.Builder() .url(//image.suning.com/1.jpg) .build()

恐怕客户端就要抛异常出来了。而大多数情况下存在这样的场景,客户端加载的请求是通过服务端返回的报文获取的,如下图所示,对于服务端系统相对协议是全局替换的,这样就会导致客户端加载请求失败。因此,就需要客户端开发对底层进行再封装,适配相对协议。

2.3 X-Request-Url的定义和使用

除了Mix Content问题,在实际HTTPS页面改造过程中,我们也遇到了另一类问题,其引发的原因是:TLS握手在统一层处理完毕,后端应用服务器无法获取原始请求协议。即是说,无论是HTTPS请求亦或是HTTP请求到达后端应用服务器都是HTTP请求。
这会造成什么问题呢?我们有部分业务逻辑跳转是在服务端根据Url拼接的,这就会导致有可能一个HTTPS请求302跳转到HTTP,触发Mix Content,最终阻塞。
我们以单点登录系统鉴权过程为例,用户在未登录情况下访问https://my.suning.com/如下图所示。

1. 用户未登录情况下,访问https://my.suning.com/,authID不存在,;
2. 请求经过接入层处理后,卸载为http://my.suning.com到业务系统,注意这时候s就已经丢失了;
3. 业务系统响应要求用户端跳转到登录系统去鉴权,同时将原页面Url: http://my.suning.com拼接在targetUrl上;
4. 用户端跳转到登录系统,发起登录请求
5. 登录请求到Passport系统,登录完成,302回跳到http://my.suning.com
6. 用户就访问到http://my.suning.com,而不是https://my.suning.com了!
如何解决类似这样的问题?我们在接入层定义了一个X-Request-Url的请求头部:

**Key**:    
X-Request-Url
**Value**:
原始协议头部(https://|http://)+ 域名 + 去参URL

这样保证了服务端能够通过X-Request-Url获取用户原始的协议头部。

3. 证书选择的细节

服务双方TLS握手过程中使用的证书需要得到权威的CA(Certificate Authority)来认证,否则通信过程就会因为证书不可信而被阻塞(自签名证书是最差的方式,不会得到浏览器信任,不在这里考虑)。如下图所示,是证书状态校验的完整过程。

那么,在证书的选择上,我们应该注意哪些细节呢?
首先,证书可以分为三类:
DV证书:Domain Validation Certificate, 信任等级普通,只需验证网站的真实性(即whois信息中的管理员邮箱验证)便可颁发证书保护网站。
OV证书:Organization Validation Certificate,信任等级强,须要验证企业的身份,审核严格,安全性更高。
EV证书:Extended Validation Certificate,认证最为严格,安全级别最高。一般会要求提供纸质材料,一般用于银行证券等金融机构。同时,大部分浏览器只针对EV证书进行CRL/OSCP的吊销检查。
而在选择证书上,我们考虑到以下多个方面:
1. 证书主机名匹配:申请的证书必须与域名匹配,否则访问时会有不匹配警告。只要有一个DNS解析指向你的TLS服务器,就必须保证你的证书包括DNS域名。
2. 是否支持多域名和泛域名:多域名和泛域名是不同的概念。多域名证书是指可以匹配多个不同的域,比如suning.com、suning.cn、suning.vip,而泛域名是指可以通过通配符匹配子域名,比如*.suning.com的泛域名证书可以匹配www.suning.com、passport.suning.com等。
DV、OV和EV对多域名和泛域名的支持如下:

证书类型单域名多域名泛域名多泛域名
DV证书支持支持不支持不支持
OV证书支持支持支持支持
EV证书支持支持不支持不支持

因此建议选择OV类证书。天猫的证书就是采用多泛域名的OV型:

*.tmall.com证书支持的域名:

DNS Name=*.tmall.com
DNS Name=*.1688.com
DNS Name=*.3c.tmall.com
DNS Name=*.alibaba.com
DNS Name=*.aliqin.tmall.com
DNS Name=*.alitrip.com
DNS Name=*.aliyun.com
...
DNS Name=taobao.com
DNS Name=taopiaopiao.com
DNS Name=tmall.hk
DNS Name=ttpod.com
DNS Name=xiami.com
DNS Name=tmall.com

3.签名算法:为了保证证书的有效性,CA在签发证书时会对证书进行数字签名。数字签名安全性依赖两个方面:一个是CA的私钥长度,一个是散列算法的强度。散列算法建议使用SHA256(SHA1由于算法强度等问题已经被CA逐渐废弃)。
SHA256存在的最大问题是兼容性问题,SP2版本及以下的Win XP以及android 2.3版本以前的移动设备不支持SHA256。
4. 证书链:一般证书链包括域名证书-中间证书-根证书,是一个能追溯到可信根证书的有序证书列表。如下所示:

- Certum Trusted Network CA
-- WoSign OV SSL CA
--- *.suning.com

证书链如果过长会降低TLS握手速度。因此建议证书链只要包含必要的证书即可。

4. CDN上证书的处理方法

CDN(Content Delivery Network, 内容传输网络)是互联网企业都会使用到的网络静态缓存和动态加速平台。然而由于自身能力限制,并不是所有电商都会自建CDN网络(自建网络基础设施的性价比着实不高),大部分电商都会购买第三方商用的CDN资源。
那么问题来了,如果要启用HTTPS,私钥必须要提供给第三方CDN。这就带来了安全隐患,毕竟一旦私钥泄露,HTTPS将一无是处。

那么有没有方案,能避免暴露私钥给到CDN厂商呢?

4.1 CDN使用双证书策略

这是一种治标不治本的方案。如下图所示,通过双证书的方案,CDN相当于反向代理,部署CDN自己的证书和私钥,与用户之间通信。CDN与服务端之间再使用服务端证书和私钥通信。这样,既保证服务端私钥不需要提供给CDN,又保证了HTTPS通信。

然而,CDN自己的私钥泄露后,黑客仍能破译用户的报文,劫持用户信息,进行中间人攻击。

4.2 CDN只启用四层加速

对于动态请求(no cache),CDN通过路径规划可以提高网络传输性能,起到加速的效果,如下图。

对于这类不需要缓存的请求,CDN完全可以基于四层TCP代理,可支持任何基于TCP传输协议的上层协议。这样CDN上就不再需要进行TLS握手,TCP以上层协议对CDN而言是黑盒。适用于购物车、提交订单、登录等场景。

4.3 CDN实现Keyless方案

Keyless解决方案是由CloudFlare公司提出的一种无证书部署解决方案(已经开源,https://github.com/cloudflare/keyless)。可以不把证书私钥给第三方,改为提供一台实时计算的 Key Server 即可。CDN 要用到私钥时,通过加密通道将必要的参数传给 Key Server,由 Key Server 算出结果并返回即可。整个过程中,私钥都保管在自己的 Key Server 之中,不会暴露给第三方。

如上图所示,
第一步 用户向CDN发起TLS握手
第二步 CDN返回公钥和证书给用户
第三步 用户端通过公钥(Public key)生成Premaster secrect(用于解密报文),发送给CDN
第四步 CDN拿到加密的Premaster secrect。由于没有私钥(Privacy Key),将Premaster secrect返回给服务端Keyless服务器。Keyless通过私钥解密出Premaster secrect返回给CDN。
第五步 完成TLS握手,基于Premaster secrect服务双方进行加密通信。

5. HTTPS测试策略

全站HTTPS改造对应用系统的调整还是比较大的,测试覆盖面广。尤其需要注意两方面:一方面是资源加载都需要使用相对协议,否则Mixed Content会阻塞请求加载;另一方面,还要保证到所有接口都支持HTTPS,否则会报net: ERR_INSECURE_RESPONSE错误。
因此,对于测试人员来说,完全依靠手工测试HTTPS不现实,需要通过测试技术,测试策略设计,和测试工具进行保证对应系统的功能质量。如下图所示,全站HTTPS功能测试主要包括四个方面。

1. 开发人员提交代码更新,在构建时,我们会通过Jenkins平台,利用shell脚本扫描SVN代码库,是否还有未修改成相对协议//的http://。
2. 测试环境爬虫验证,研发提测后,使用爬虫程序对对应的应用进行扫描,使用正则表达式和页面请求返回code(Mixed Content/net: ERR_INSECURE_RESPONSE),进行验证,来爬取有问题的页面。
3. 测试环境,核心主流程使用HTTPS,手工验证。当然大部分的bug在前两部中应该可以被修复掉。
4. 最终,HTTPS版本预发到生成环境上,只要我们不做强制HTTPS,用户是感知不到的。再通过引流工具引流用户的HTTP流量,改造成HTTPS流量,进行线上环境的引流测试。

至此,全站HTTPS系统改造篇完结,下一篇我们开启对HTTPS的性能优化。

以上是关于电商网站HTTPS实践之路——系统改造篇的主要内容,如果未能解决你的问题,请参考以下文章

电商网站HTTPS实践之路——灰度上线篇

电商网站HTTPS实践之路——概述篇

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

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

申通的云原生实践之路:如何实现应用基于容器的微服务改造?

广播电视新闻网站HTTPS改造探讨