一、全站HTTPS准备工作
◎制定整个HTTPS改造计划
接下来就是了解整个业务线、核心系统,nginx代理配置。统计出所有已用到的域名,需要购买什么类型域名证书,泛域名证书、二级域名、三级域名还等,分析统计;再然后,了解每个域名背后的服务是如何运作的,这里边会涉及到前端页面、一些资源文件的固定协议引用,后端代码中关于协议获取是写死的还是动态的,数据库中存储的网址链接等等,这些统统要考虑到。
分析完系统后,其中肯定会存在混合协议访问请求,HTTPS 下浏览器会拦截掉所有 HTTP 请求的,不同页面间跳转、不同服务域名间跳转如果是以固定的 HTTP 协议写死的,要支持全站 HTTPS 协议,首要解决的是以当前协议来灵活的区分不同域名服务间的跳转。其次,HTTPS 协议首次请求存在多次握手,因此网络耗时变长问题,可能会影响系统访问速度。所以,建议计划分为两个阶段来进行全站 HTTPS 升级:
沟通阶段:与开发沟通系统是否需要https改造及影响面,周知系统的调用方是否需要改造;同时在代理层配置好证书并验证
一阶段:将目前所有域名配置为支持 HTTP 和 HTTPS 两种协议,不做 HTTP 请求强制 HTTPS 跳转。在验证及测试完成 HTTPS 下,系统所有服务以及访问速度均无问题后,进行实施二阶段计划。
二阶段:在上阶段不强制 HTTPS 访问验证通过后,域名做强制 HTTPS 协议。即当用户以 HTTP 协议访问系统时, 如用 Nginx 做强制 301 跳转到 HTTPS 协议,做到全站 HTTPS 安全访问协议。
set $sslparam ""; if ( $server_port = 443 ) { set $sslparam on; } if ( $http_x_forwarded_proto = "https" ) { set $sslparam on ; } if ( $http_sslparam = "https" ) { set $sslparam on; } if ( $request_uri ~* "login.php\?mod=logging\&action=callback" ) { # login接口未改造完成,允许http协议先访问 set $sslparam on ; } if ( $sslparam != "on" ) { return 301 https://$host$request_uri; }
不出意外,按照这两步计划,应该可以稳妥是进行全站 HTTPS 升级工作,当然,期间不可避免的会踩一些坑,因为每个公司业务不同、系统环境不同等原因,都会遇到不可预估的问题,一个个解决就行了。我下面会写一下升级期间共性的、也就是每个人都必须要踩的坑和如何解决这些问题。
云厂商代理层HTTP强跳HTTPS:
二、HTTPS改造注意事项
1) 浏览器拦截混合访问请求
由于浏览器安全规则,在 HTTPS 请求下通过 JavaScript 请求 HTTP 请求或引入 HTTP 协议资源文件,会报“Mixed Content”错误,导致请求无法
Mixed Content: The page at 'https://domain.com/' was loaded over HTTPS, but requested an insecure script 'http://domain.com/'. This request has been blocked; the content must be served over HTTPS.
2) 前端 HTML、JS 资源引用存在 HTTP
前端页面及 js 文件中,写死的
http://
协议资源及跳转改为根据当前协议切换(//
)。使用相对协议,如:
<script src="//domain.com/jquery.js"></script> <img src="//domain.com/img/logo.png">
或者代码自行判断都可以。如果一个页面内包含多个域名请求,需所有域名均支持https,否则部分浏览器会有警告提醒或打不开。
3) 移动端适配 HTTPS
如果你们存在移动客户端(APP)也需要适配 HTTPS,所以必须做调用接口的相应修改,当然,要注意运营商 DNS 劫持(尤其是移动)也会对 HTTPS 请求成功率造成很大影响,其实可以做好 HTTP/HTTPS 两种协议都支持,做好出问题随时动态降级切换准备。
4) 项目中存在的配置问题
项目中用到的配置文件中存在 HTTP 链接,要充分了解其用途。如果不是可以统一动态更新的配置文件,都要考虑更改后做服务的发布,这时候要来考虑对生产环境业务的影响以及测试、开发环境的影响等问题。如页面间跳转、权限、登录验证、第三方服务(支付、推送)回调这些配置等。
5) SSL 证书类型
选购 SSL 证书的时候,需要充分考虑业务上域名需要的证书类型,避免需要泛域名证书而你买了单域名证书,当然泛域名证书还是分为支持级别的,如购买
*.
example.com
证书,那么该证书支持a.example.com
,
a1.example.com
,
a2.example.com
以此类推域名,但是不支持b.a.example.com
(另一级),
b1.a.example.com
类域名,如需支持,需另外再购买一张*.
a.example.com
证书。
6) 关于 request.getScheme()
这个坑
如果你的架构上使用了 Nginx + Tomcat 集群, 且 Nginx 下配置了 SSL ,Tomcat 没有配置 SSL ,这时候其实客户端已经是使用 HTTPS 协议了,但你的 Tomcat 中用
request.getScheme()、request.getRequestURL()
会获取到的是 HTTP,并不是 HTTPS 。当然可以代码中避免,或者通过配置 Nginx 和 Tomcat 解决,看这篇文章:http://www.cnblogs.com/interdrp/p/4881785.html
7) Nginx 配置 HTTP 强制跳转 HTTPS
通过配置 Nginx 域名 HTTP 请求 301,302 跳转实现全站 HTTPS。开启https强制跳转后,302/301跳转只是将http转换为https,如果有 POST 请求,这时候浏览器可能会先做跳转,如果客户端不继续推送请求那么就会丢失参数,再以 Get 方法请求会导致 Post Body 丢失,导致没有响应,在浏览器内访问正常是因为浏览器会在收到302响应之后重新提交一次参数然后响应成功。可以在强跳时返回307状态码解决此问题,307就是在重定向中依旧保持原有的数据。
if ($scheme = http ) { return 307 https://$host$request_uri; }
强跳https后大量308状态码说明调用方有http来源请求跳转了,需要观察服务日志,及时回滚,关注报警情况。http请求url如果是在浏览器访问,会自动跳转https访问,但如果是通过接口访问,会直接返回308跳转后不会再次转https访问,这个时间就拿不到返回,存在问题。
The RFC 7231, the current reference for semantics and content of the HTTP/1.1 protocol, defines the
301
(Moved Permanently) and302
(Found) status code, that allows the request method to be changed fromPOST
toGET
. This specification also defines the307
(Temporary Redirect) status code that doesn't allow the request method to be changed fromPOST
toGET
.
+-----------+-----------+ | Permanent | Temporary | +------------------------------------------------------------+-----------+-----------+ | Allows changing the request method from POST to GET | 301 | 302 | +------------------------------------------------------------+-----------+-----------+ | Doesn't allow changing the request method from POST to GET | 308 | 307 | +------------------------------------------------------------+-----------+-----------+
Choosing the most suitable status code
Michael Kropat put together a set of decision charts that helps to determine the best status code for each situation. See the following for 2xx
and 3xx
status codes:
8) CDN站点配置 HTTP 强制跳转 HTTPS
静态站点域名切https强跳需在cdn上关闭http访问,只开启https跳转,考虑调用方太多,影响太大,可以放在最后操作
cdn域名切强跳影响很大,尤其是涉及全球化的域名,因此在域名切换前,要注意cdn厂商和源站的缓存策略是否一致,做好域名的url监控,由于切换存在一定时间段的生效时延,需通过拨测验证各区域是否达到效果。同时需要做好回滚的方案,特别是cdn节点缓存的问题,回滚后一定要刷新一下。反正各种奇葩的问题出现不少
9) Android、IOS等app端改造
注意点:
1、有些域名在低版本中有。
2、有部分功能是之前版本有,现在已经下掉了的。
3、有些功能的url是后台下发的。
解决方案:
针对(1和2):
当低版本app占比非常低时(例如:低于1%),可使用强制升级将低版本升级成兼容https的版本。
针对3:两种方案,
1、后端下发的url做https兼容处理,都处理成https的。
2、app端检测下发的http域名,将其做https兼容。
需统计好各历史阶段版本受影响的域名,以及各版本app上线时间和对应用户占比及功能上下线情况
10) 所有环境均要进行升级
不仅仅要考虑生产环境进行全站 HTTPS 升级问题,包括开发、测试、预发布等多种不同环境均要进行升级,来保持与生产环境的一致性,减小不可预估因素的发生。(可延后,优先生产环境改造)
三、域名回滚及问题记录
目前遇到的难点:
1、很多接口调用没有referer,kibana上没有区分http和https协议,通过来源IP难定位到对应调用方
2、变更时无法周知所有调用方,很难确定整体影响面,调用方反馈问题才回滚有一定时间差
3、存在老接口,老服务调用的情况,难以定位到来源请求方,阻塞https改造进度
4、有些项目负责人是新接手的,改造沟通测试、问题定位也存在一些成本
5、涉及外边第三方公司调用,目前sre无法整体把控,需要rd反馈推动第三方改https调用
6、代码中存在硬编码,且业务无法灰度,改造影响面大的服务需和SRE确定方案后再执行
7、改造推动依赖于RD排期和投入力度,存在延时的风险
8、cdn域名切强跳影响面大,涉及第三方cdn厂商协作,响应慢,操作流程长;定位、排查问题费劲
9、 Android、IOS等app端改造涉及不同版本,部分老功能存在硬编码,低版本app改造难度大,周期长
10、有些第三方公司调用的域名(如支付域名)存储到第三方的数据库的老链接无法修改,历史数据调用时可能存在风险,
比如历史数据的退款通知还是会使用http请求,需要保证https跳转后请求参数完整,能正常响应
域名回滚记录:
回滚时间 | 回滚域名 | 问题现象 | 备注 |
---|---|---|---|
2020 | file.chegva.com | 1.存在308状态码 2.引用图片加载失败 | 自身服务需改造,同时推动调用方改造 |
2021 | test.chegva.com | 1.存在少量308状态码 2./gettime接口有来自c.chegva.com的http流量请求 | 1.周知c.chegva.com的负责人确认是否代码中存在写死http请求的情况 2.由于c.chegva.com接了cdn,有可能存在cdn那边来的http请求情况,需协调cdn厂商先给c.chegva.com加强跳https,再验证 |
2022 | cdn.chegva.com | 1.切完强跳后,海外少部分cdn监测点301跳转报警,绑定cdn节点测试访问正常 2.强跳回滚后,部分节点依然报301跳转报警,通知cdn厂商刷新缓存后解决 | 1.切完强跳后监控url正常不应该有301跳转的报警(监控url链接本身就是走https),需联系cdn厂商确认原因 怀疑点: 1)监控探测的问题? 2)部分节点缓存的问题? |