浅谈推进全站 HTTPS 项目 - 工程篇

HTTPS 在 HTTP 的基础上增加了 SSL/TLS 加密,提供了更加安全的传输协议。俨然已经属于各大网站的标配。有赞作为一个 SaaS 平台,涉及到用户的商品,交易,支付等关键性流程。支持全站 HTTPS,提高网站安全是我们的基础保障。本文关注的事情包括: 了解 HTTPS 基础原理,切换 HTTPS 需要切换的内容,如何监控和实际操作,以及遇到的一些难点。

一、基本原理

在原有 HTTP 握手的基础上,增加了证书的验证,进行了加密,这样我们传输数据就有安全的保证。解决的问题包括运营商劫持中间人攻击钓鱼网站提升SEO等。具体流程如下:

  1. 客户端发送“ClientHello”消息,消息包含 SSL 的版本、客户端支持的加密套件和数据压缩算法及随机数 1。
  2. 服务器响应“ServerHello”消息,消息包含选定的加密套件、选定的数据压缩方法、会话标识,数字证书及另一个随机数 2。
  3. 客户端( Web 浏览器)验证服务器的 SSL 数字证书的有效性,不通过则提示警告。
  4. 客户端发送“客户端密钥交换”消息。此消息包含 pre-master secret(用于生成对称加密密钥生的随机数 3)。
  5. 客户端使用一系列加密运算将 [随机数 1 随机数 2 随机数 3] 转化为 master secret,其中将派生出所有用于加密和消息认证的密钥。
  6. 服务器使用一系列加密运算将 [随机数 1 随机数 2 随机数 3] 转化为 master secret,其中将派生出所有用于加密和消息认证的密钥。
  7. 客户端发出“更改密码规范”通知服务器端之后使用协商好的对称加密算法及密钥通信。
  8. 服务器发出“更改密码规范”通知客户端之后使用协商好的对称加密算法及密钥通信。
  9. SSL 握手结束,使用对称加密算法进行加密通信。

二、 切换需要涉及的资源和服务

当你开始着手切换成 HTTPS 的工作时,首先你需要明确你要处理的内容有什么? 一般来说你需要梳理以下内容:

  1. 部署到 cdn 的静态资源,js、css
  2. 图片资源
  3. 主域及其次级域名的数量
  4. 是否有第三方资源,比如广告、视频等接入
  5. api 调用,是否动态返回 HTTP 业务
  6. 提供的对外服务

关于第 1 点,静态资源基本会收敛于少数域名,服务也基本会由第三方 cdn 服务商提供。 对应的服务提供商处开启 HTTPS 支持。

动态引入静态资源


<link rel="stylesheet" href="${loadStaticContent(www/css/main.min.css)}">

<script type="text/javascript"  src="${loadStaticContent(www/js/main.min.js)}"></script>

在早期全站加载静态资源过程中, 应该自定义前端模板方法去动态加载 js,css。 防止写死域名情况。后期在全站切 cdn 域名时,就可以直接使用新的 HTTPS 域名,一刀切,修改模板方法引入域名和路径。

关于第 2 点,图片来源一般分为两种,站内图片和站外图片。站内图片,基本会使用第三方 cdn 服务。可以统一开启 HTTPS。而站外图片一般的来源可能包括:开发写死,对接第三方服务(类似淘宝导购),链接型图片上传未存储到自己的服务。

css 动态引入图片

.loading {
    background-image: image-cdn('/logo_loading.png');
}

假设使用了 sass 等工具,站内图片可以在 css 中引入 cdn 域名加载方法。统一替换。

老图片问题

对于老的 HTTP 数据图片数据,业务访问可知的情况下,需要跑脚本重新上传。对于上传图片组件若传入的是 HTTP 图片,应该考虑重新上传支持。

关于第 3 点,主域及其次级域名,可以通过统计 nginx 日志上 HTTP 的流量 (awk 日志)。获取现有站点 HTTP 流量的 pv 访问表。得到需要 HTTPS 的域名的数量。确认切换 HTTPS 顺序和工期,考虑因素包括:请求量的大小业务的轻重缓急业务切换 HTTPS 难度各域名功能等方面。在确定站点基本情况后,需要和各业务方交流以上方面问题。得出各域名切换的时间节点。

关于第 4 点,第三方资源引入问题。

  • 视频应该使用引入支持 HTTPS 的视频资源,比如腾讯视频。
  • 外站不支持 HTTPS 图片,应该考虑重传为站内图片。
  • 广告对接,一般是引入第三方广告脚本,第三方脚本做什么事情,都属于第三方脚本的工作, 所以需要脚本提供方提供 HTTPS 服务

原则上第三方资源应该是 HTTPS 的,如果不是,我们可能就需要存储到自己的服务上或者通过服务端转发。否则必然是 HTTPS 的环境下,引入 HTTP 的情况

关于第 5 点,属于业务范畴,前端走 api 方式的调用,返回值中针对头像、展示图片等图片方式,如果经过模板层可以考虑加模板方式统一替换成 HTTPS,直接拼装成的字符串。可以提供统一方法替换。

关于第 6 点 ,比如你有 api 等对外服务。早期开放了 HTTP 调用的口子,那么很遗憾。我们能做的事情是通过公告、邮件等方式告知第三方,我们在特定时间后就不在支持 HTTP 服务,希望第三方支持 HTTPS 调用。或者如果安全性不重要的话,那么就同时支持 HTTP/HTTPS 调用。苹果 HTTPS 的公告App Transport Security就是很好的例子,而实际上 app 内部还是留了开启
HTTP 请求的设置。

以上是需要我们处理的大部分内容。在推进全站 HTTPS 问题之前,做好这步梳理准备。包括了调研确认切换范围了解业务切换难易程度确定工作的时间安排和参与人员。注:各部分工作设定好 deadline,会对你有非常大的帮助。

三、切换 HTTPS 中的注意点

站内 HTTPS 资源准备完毕后,就可以考虑将各站点切换成 HTTPS。操作层面需要注意以下几点:

相对协议

代码层面对明显写死的 HTTP 协议进行修改。修改成相对协议是不错的选择

<img src="//domain.com/img/logo.png">
<script src="//www/js/libs/jquery/1.4.2/jquery.js"></script>

相对协议下,当你访问 HTTPS 网站时,请求 HTTPS 资源。否则 HTTP。这样方案上更具有灵活性,可以考虑内网先进行 HTTPS 的测试,对外网使用 HTTP。 假设 HTTPS 方案出现问题时,可退回到 HTTP。

301 与 302 区别

当页面所有资源都切换成 HTTPS,回归测试后。可考虑 HTTP 访问网站时, nginx 302重定向到 HTTPS。强制切换。上线后可经过几天到一周的观察。(流量大和复杂业务需要更久)业务稳定, 无异常及用户反馈情况。可以强制301切换。

302 和 301 的区别就在于:302 重定向是临时的,下次浏览器访问同样是访问原链接。而 301 重定向是持久的。下次浏览器会直接访问新链接。所以当确定某域名下已经实现了 HTTPS,可采用 301 重定向。

Content-Security-Policy

当某站点已经切换成了 HTTPS 。假设后期还是有开发人员引入 HTTP 的情况。我们应该采用哪种 CSP 策略防止呢?

block-all-mixed-content, 强制阻止页面内 HTTP 加载

<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">

但是实际上,阻止 HTTP 加载不是我们的目的,后期开发中
引入 HTTP 的行为可能是疏漏造成的,我们可以理解成实际上资源已经可以支持 HTTPS 的。 所以可以采用另一种 CSP 策略: upgrade-insecure-requests

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

该策略下会产生以下两种效果
- 站点内的 HTTP 请求,都会 HTTPS 的方式发起。
- 所有连接跳转都会以 HTTPS 的方式打开。

这种策略显然更加友好。当网站已经确认强制使用了 HTTPS,就可以加入该方法。

测试环境是否启用 HTTPS

从测试便利性角度,测试环境可以提供 Http。但实际上为了和正式环境一致应该用
HTTPS 测试更合理。因为上述推荐使用相对协议,所以测试环境本身是可以提供
Http/HTTPS 两种方案的。

四、遇到的难点

全站 HTTPS 由于域名和业务等因素影响,切换过程中必然会遇到许多难点。 主要表现在业务方来源和用户访问来源:

  1. 基础接口调用方太多,同时存在前端直接调用或者后端业务层调用的情况,需要接口提供方定位接口真实调用位置。
  2. 一些接口调用没有 referer,referer 对于前端定位流量来源能够提供非常大的帮助。但是有一些页面的 Http 访问不存在 referer,这种情况可能由于用户保存该页面链接或者从其他来源进入网站页面丢失等造成。假设页面经过 HTTPS
    测试通过,可以通过强制切换成 HTTPS 解决。
  3. 客户端接口老版本请求 HTTP 情况,根据用户的量,判断是否放弃老版本的调用。否则无法根除该流量的 HTTP
  4. 第三方请求公司提供的 HTTP 服务, 告知第三方规定时间内升级。

除了以上的几个显性难点外,其实还有些隐性难点,比如需要与业务方约定明确强制切换的 deadline,接口升级、服务改造迁移、老接口复杂性等各种问题都会拖延各实施方的进度。只有强制的 deadline 切换才保住全站 HTTPS 的推进进度。

写在最后,本文主要是围绕推动公司全站 HTTPS 的一些心得。更多的是以一个项目推动方的角度考虑如何推动事情的落地。原理,内容,执行,难点。这几个核心流程把握住。我们才能做到更加有条理的实施。同时全站流量切换成 HTTPS,其实只是工作的开始。之后的 HTTPS 性能优化、异常 HTTP 流量监控、HTTPS 可用性监控等都是接下来应该去不断推进的工作。