百度:大型网站的 HTTPS 实践(下)
来源:百度运维
第三部分:基于协议和配置的优化
上篇讲到 HTTPS 对用户访问速度的影响。第三部分将为大家介绍 HTTPS 在访问速度,计算性能,安全等方面基于协议和配置的优化。
HTTPS 访问速度优化
1. Tcp fast open
HTTPS 和 HTTP 使用 TCP 协议进行传输,也就意味着必须通过三次握手建立 TCP 连接,但一个 RTT 的时间内只传输一个 syn 包是不是太浪费?能不能在 syn 包发出的同时捎上应用层的数据?其实是可以的,这也是 tcp fast open 的思路,简称 TFO。具体原理可以参考 rfc7413。
遗憾的是 TFO 需要高版本内核的支持,linux 从 3.7 以后支持 TFO,但是目前的 windows 系统还不支持 TFO,所以只能在公司内部服务器之间发挥作用。
2. HSTS
前面提到过将用户 HTTP 请求 302 跳转到 HTTPS,这会有两个影响:
1, 不安全,302 跳转不仅暴露了用户的访问站点,也很容易被中间者支持。
2, 降低访问速度,302 跳转不仅需要一个 RTT,浏览器执行跳转也需要执行时间。
由于 302 跳转事实上是由浏览器触发的,服务器无法完全控制,这个需求导致了 HSTS 的诞生:
HSTS(HTTP Strict Transport Security)。服务端返回一个 HSTS 的 http header,浏览器获取到 HSTS 头部之后,在一段时间内,不管用户输入www.baidu.com 还是 http://www.baidu.com,都会默认将请求内部跳转成https://www.baidu.com。
Chrome, firefox, ie 都支持了 HSTS (http://caniuse.com/#feat=stricttransportsecurity)。
3. Session resume
Session resume 顾名思义就是复用 session,实现简化握手。复用 session 的好处有两个:
1, 减少了 CPU 消耗,因为不需要进行非对称密钥交换的计算。
2, 提升访问速度,不需要进行完全握手阶段二,节省了一个 RTT 和计算耗时。
TLS 协议目前提供两种机制实现 session resume,分别介绍一下。
3.1 Session cache
Session cache 的原理是使用 client hello 中的 session id 查询服务端的 session cache, 如果服务端有对应的缓存,则直接使用已有的 session 信息提前完成握手,称为简化握手。
Session cache 有两个缺点:
1, 需要消耗服务端内存来存储 session 内容。
2, 目前的开源软件包括 nginx,apache 只支持单机多进程间共享缓存,不支持多机间分布式缓存,对于百度或者其他大型互联网公司而言,单机 session cache 几乎没有作用。
Session cache 也有一个非常大的优点:
1, session id 是 TLS 协议的标准字段,市面上的浏览器全部都支持 session cache。
百度通过对 TLS 握手协议及服务器端实现的优化,已经支持全局的 session cache,能够明显提升用户的访问速度,节省服务器计算资源。
3.2 Session ticket
上节提到了 session cache 的两个缺点,session ticket 能够弥补这些不足。
Session ticket 的原理参考 RFC4507。简述如下:
server 将 session 信息加密成 ticket 发送给浏览器,浏览器后续握手请求时会发送 ticket,server 端如果能成功解密和处理 ticket,就能完成简化握手。
显然,session ticket 的优点是不需要服务端消耗大量资源来存储 session 内容。
Session ticket 的缺点:
1, session ticket 只是 TLS 协议的一个扩展特性,目前的支持率不是很广泛,只有 60% 左右。
2, session ticket 需要维护一个全局的 key 来加解密,需要考虑 KEY 的安全性和部署效率。
总体来讲,session ticket 的功能特性明显优于 session cache。希望客户端实现优先支持 session ticket。
4. Ocsp stapling
Ocsp 全称在线证书状态检查协议 (rfc6960),用来向 CA 站点查询证书状态,比如是否撤销。通常情况下,浏览器使用 OCSP 协议发起查询请求,CA 返回证书状态内容,然后浏览器接受证书是否可信的状态。
这个过程非常消耗时间,因为 CA 站点有可能在国外,网络不稳定,RTT 也比较大。那有没有办法不直接向 CA 站点请求 OCSP 内容呢?ocsp stapling 就能实现这个功能。
详细介绍参考 RFC6066 第 8 节。简述原理就是浏览器发起 client hello 时会携带一个 certificate status request 的扩展,服务端看到这个扩展后将 OCSP 内容直接返回给浏览器,完成证书状态检查。
由于浏览器不需要直接向 CA 站点查询证书状态,这个功能对访问速度的提升非常明显。
Nginx 目前已经支持这个 ocsp stapling file,只需要配置 ocsp stapling file 的指令就能开启这个功能:
ssl_stapling on;ssl_stapling_file ocsp.staple; |
5. False start
通常情况下,应用层数据必须等完全握手全部结束之后才能传输。这个其实比较浪费时间,那能不能类似 TFO 一样,在完全握手的第二个阶段将应用数据一起发出来呢?google 提出了 false start 来实现这个功能。详细介绍参考https://tools.ietf.org/html/draft-bmoeller-tls-falsestart-00。
简单概括 False start 的原理就是在 client_key_exchange 发出时将应用层数据一起发出来,能够节省一个 RTT。
False start 依赖于 PFS(perfect forward secrecy 完美前向加密),而 PFS 又依赖于 DHE 密钥交换系列算法 (DHE_RSA, ECDHE_RSA, DHE_DSS, ECDHE_ECDSA),所以尽量优先支持 ECDHE 密钥交换算法实现 false start。
6. 使用 SPDY 或者 HTTP2
SPDY 是 google 推出的优化 HTTP 传输效率的协议(https://www.chromium.org/spdy),它基本上沿用了 HTTP 协议的语义, 但是通过使用帧控制实现了多个特性,显著提升了 HTTP 协议的传输效率。
SPDY 最大的特性就是多路复用,能将多个 HTTP 请求在同一个连接上一起发出去,不像目前的 HTTP 协议一样,只能串行地逐个发送请求。Pipeline 虽然支持多个请求一起发送,但是接收时依然得按照顺序接收,本质上无法解决并发的问题。
HTTP2 是 IETF 2015 年 2 月份通过的 HTTP 下一代协议,它以 SPDY 为原型,经过两年多的讨论和完善最终确定。
本文就不过多介绍 SPDY 和 HTTP2 的收益,需要说明两点:
1, SPDY 和 HTTP2 目前的实现默认使用 HTTPS 协议。
2, SPDY 和 HTTP2 都支持现有的 HTTP 语义和 API,对 WEB 应用几乎是透明的。
Google 宣布 chrome 浏览器 2016 年将放弃 SPDY 协议,全面支持 HTTP2,但是目前国内部分浏览器厂商进度非常慢,不仅不支持 HTTP2,连 SPDY 都没有支持过。
百度服务端和百度手机浏览器现在都已经支持 SPDY3.1 协议。
HTTPS 计算性能优化
1. 优先使用 ECC
ECC 椭圆加密算术相比普通的离散对数计算速度性能要强很多。下表是 NIST 推荐的密钥长度对照表。
对称密钥大小 | RSA 和 DH 密钥大小 | ECC 密钥大小 |
80 | 1024 | 160 |
112 | 2048 | 224 |
128 | 3072 | 256 |
192 | 7680 | 384 |
256 | 15360 | 521 |
表格 2 NIST 推荐使用的密钥长度
对于 RSA 算法来讲,目前至少使用 2048 位以上的密钥长度才能保证安全性。ECC 只需要使用 224 位长度的密钥就能实现 RSA2048 位长度的安全强度。在进行相同的模指数运算时速度显然要快很多。
2. 使用最新版的 openssl
一般来讲,新版的 openssl 相比老版的计算速度和安全性都会有提升。比如 openssl1.0.2 采用了 intel 最新的优化成果,椭圆曲线 p256 的计算性能提升了 4 倍。(https://eprint.iacr.org/2013/816.pdf)
Openssl 2014 年就升级了 5 次,基本都是为了修复实现上的 BUG 或者算法上的漏洞而升级的。所以尽量使用最新版本,避免安全上的风险。
3. 硬件加速方案
现在比较常用的 TLS 硬件加速方案主要有两种:
1, SSL 专用加速卡。
2, GPU SSL 加速。
上述两个方案的主流用法都是将硬件插入到服务器的 PCI 插槽中,由硬件完成最消耗性能的计算。但这样的方案有如下缺点:
1, 支持算法有限。比如不支持 ECC,不支持 GCM 等。
2, 升级成本高。
a) 出现新的加密算法或者协议时,硬件加速方案无法及时升级。
b) 出现比较大的安全漏洞时,部分硬件方案在无法在短期内升级解决。比如 2014 年暴露的 heartbleed 漏洞。
3, 无法充分利用硬件加速性能。硬件加速程序一般都运行在内核态,计算结果传递到应用层需要 IO 和内存拷贝开销,即使硬件计算性能非常好,上层的同步等待和 IO 开销也会导致整体性能达不到预期,无法充分利用硬件加速卡的计算能力。
4, 维护性差。硬件驱动及应用层 API 大部分是由安全厂家提供,出现问题后还需要厂家跟进。用户无法掌握核心代码,比较被动。不像开源的 openssl,不管算法还是协议,用户都能掌握。
4. TLS 远程代理计算
也正是因为上述原因,百度实现了专用的 SSL 硬件加速集群。基本思路是:
1, 优化 TLS 协议栈,剥离最消耗 CPU 资源的计算,主要有如下部分:
a) RSA 中的加解密计算。
b) ECC 算法中的公私钥生成。
c) ECC 算法中的共享密钥生成。
2, 优化硬件计算部分。硬件计算不涉及协议及状态交互,只需要处理大数运算。
3, Web server 到 TLS 计算集群之间的任务是异步的。即 web server 将待计算内容发送给加速集群后,依然可以继续处理其他请求,整个过程是异步非阻塞的。
HTTPS 安全配置
1. 协议版本选择
SSL2.0 早就被证明是不安全的协议了,统计发现目前已经没有客户端支持 SSL2.0,所以可以放心地在服务端禁用 SSL2.0 协议。
2014 年爆发了 POODLE 攻击,SSL3.0 因此被证明是不安全的。但是统计发现依然有 0.5% 的流量只支持 SSL3.0。所以只能有选择地支持 SSL3.0。
TLS1.1 及 1.2 目前为止没有发现安全漏洞,建议优先支持。
2. 加密套件选择
加密套件包含四个部分:
1, 非对称密钥交换算法。建议优先使用 ECDHE,禁用 DHE,次优先选择 RSA。
2, 证书签名算法。由于部分浏览器及操作系统不支持 ECDSA 签名,目前默认都是使用 RSA 签名,其中 SHA1 签名已经不再安全,chrome 及微软 2016 年开始不再支持 SHA1 签名的证书 (http://googleonlinesecurity.blogspot.jp/2014/09/gradually-sunsetting- sha-1.html)。
3, 对称加解密算法。优先使用 AES-GCM 算法,针对 1.0 以上协议禁用 RC4( rfc7465)。
4, 内容一致性校验算法。Md5 和 sha1 都已经不安全,建议使用 sha2 以上的安全哈希函数。
3. HTTPS 防攻击
3.1 防止协议降级攻击
降级攻击一般包括两种:加密套件降级攻击 (cipher suite rollback) 和协议降级攻击(version roll back)。降级攻击的原理就是攻击者伪造或者修改 client hello 消息,使得客户端和服务器之间使用比较弱的加密套件或者协议完成通信。
为了应对降级攻击,现在 server 端和浏览器之间都实现了 SCSV 功能,原理参考 https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00。
一句话解释就是如果客户端想要降级,必须发送 TLS_SCSV 的信号,服务器如果看到 TLS_SCSV,就不会接受比服务端最高协议版本低的协议。
3.2 防止重新协商攻击
重新协商(tls renegotiation)分为两种:加密套件重协商 (cipher suite renegotiation) 和协议重协商(protocol renegotiation)。
重新协商会有两个隐患:
1, 重协商后使用弱的安全算法。这样的后果就是传输内容很容易泄露。
2, 重协商过程中不断发起完全握手请求,触发服务端进行高强度计算并引发服务拒绝。
对于重协商,最直接的保护手段就是禁止客户端主动重协商,当然出于特殊场景的需求,应该允许服务端主动发起重协商。
小结:HTTPS 的实践和优化涉及到了非常多的知识点,由于篇幅关系,本文对很多优化策略只是简单介绍了一下。
如果想要了解协议背后的原理,还是需要详细阅读 TLS 协议及 PKI 知识。对于大型站点来说,如果希望做到极致,HTTPS 的部署需要结合产品和基础设施的架构来进行详细的考虑,比起部署支持 HTTPS 的接入和对它的优化,在产品和运维层面上花费的功夫会更多,第四部分将详细介绍。
第四部分:协议层以外的实践
网上介绍 https 的文章并不多,更鲜有分享在大型互联网站点部署 https 的实践经验,我们在考虑部署 https 时也有重重的疑惑。这里为大家介绍百度 HTTPS 的实践和一些权衡, 希望以此抛砖引玉。
协议层以外的实践工作
1. 全站覆盖 https 的理由
很多刚接触 https 的会思考,我是不是只要站点的主域名换了 https 就可以?答案是不行。
https 的目的就是保证传输过程的安全,如果只有主域名上了 https,但是主域名加载的资源,比如 js,css,图片没有上 https,会怎么样?
从效果上来说,没有达到保证网站传输过程安全的目的,因为你的 js,css,图片仍然有被劫持的可能性,如果这些内容被篡改 / 嗅探了,那么 https 的意义就失去了。
浏览器在设计上早就考虑的这样的情况,会有相应的提示。具体的实现依赖浏览器,例如地址栏锁形标记从绿色变为黄色, 阻止这次请求,或者直接弹出非常影响用户体验的提示 (主要是 IE),用户会感觉厌烦,疑惑和担忧安全性。
很多用户看见这个链接会习惯性的点”是”,这样非 https 的资源就被禁止加载了。非 ie 的浏览器很多也会阻止加载一些危害程度较高的非 https 资源(例如 js)。我们发现移动端浏览器的限制目前会略松一些。
所以这里要是没做好,很多情况连网站的基本功能都没法正常使用。
2. 站点的区别
很多人刚接触 https 的时候,觉得不就是部署证书,让 webserver 支持 https 就行了吗。
实际上对于不同的站点来说,https 的部署方式和难度有很大的区别。对于一个大型站点来说,让 webserver 支持 https,以及对 webserver 在 https 协议特性上做一些优化,在迁移的工作比重上,可能只占到 20%到40%。
我们考虑在以下几种情况下部署 https 的方案。
2.1 简单的个人站点
简单的定义:资源只从本站的主域或者主域的子域名加载。
比如 axyz 的个人 blog,域名是 axyzblog.com。加载主域名下的 js 和图片。
这样的站部署 https,在已有证书且 webserver 支持的情况下,只需要把主域名替换为 https 接入,然后把资源连接修改为 https:// 或者 //。
2.2 复杂的个人站点
复杂的定义:资源需要从外部域名加载。
这样就比较麻烦了,主域资源容易适配 https,在 cdn 上加载的资源还需要 cdn 服务商支持 https。目前各大 cdn 的服务商正在逐渐提供 https 的支持,需要迁移的朋友可以看看自己使用的 cdn 是否提供了这项能力。一些 cdn 会对 https 流量额外收费。
Cdn 使用 https 常见的方案有:
1 网站主提供私钥给 cdn,回源使用 http。
2 cdn 使用公共域名,公共的证书,这样资源的域名就不能自定义了。回源使用 http。
3 仅提供动态加速,cdn 进行 tcp 代理,不缓存内容。
4 CloudFlare 提供了Keyless SSL的服务,能够支持不愿意提供私钥, 不想使用公共的域名和证书却又需要使用 cdn 的站点了。
2.3 简单的大型站点
简单的定义: 资源只从本站的主域, 主域的子域,或者自建 / 可控的 cdn 域名加载,几乎没有第三方资源。如果网站本身的特性就如此,或愿意改造为这样的类型,部署 https 就相对容易。Google和Twitter 都是非常好的范例。优点:已经改成这样的站点,替换 https 就比较容易。缺点:如果需要改造,那么要很大的决心,毕竟几乎不能使用多样化的第三方资源了。
2.4 复杂,访问速度重要性稍低的大型站点
复杂的定义:从本站的非主域,或者第三方站点的域名有大量的第三方资源需要加载,多出现在一些平台类,或者有复杂内容展现的的网站。
访问速度要求:用户停留时间长或者强需求,用户对访问速度的耐受程度较高。比如门户,视频,在线交易类(比如火车票 机票 商城)网站。
这样的站点,可以努力推动所有相关域名升级为支持 https。我们用下图举例说明下这样修改会导致一个网站的链接发生怎样的改变。
负责流量接入的团队将可控的接入环境改造为 http 和 https 都支持,这样前端工程的工作相对就少一些。大部分时候将链接从 http:// 替换为 // 即可。在主域名是 https 的情况下,其它资源就能自动从 https 协议下加载。一些第三方资源怎么办?一般来说只有两种选择,一迁移到自己的 cdn 或者 idc 吧,二强制要求第三方自己能支持 https。
以全站 https 接入的 facebook 举例。第三方厂商想在 facebook 上线一个游戏。facebook:请提供 https 接入吧。第三方想:能赚钱啊,还是提供下 https 接入吧。所以,足够强势,有吸引力,合作方也有提供 https 的能力的话,这是完全可行的。如果你的平台接入的都是一些个人开发者,而且还赚不到多少钱的情况下,这样就行不通了。
优点:前端改动相对简单,不容易出现 https 下还有 http 的资源问题。
缺点:通常这样的实现下,用户的访问速度会变慢,比如从 2.5 秒变为 3 秒,如上述的理由,用户还是能接受的。对第三方要求高。
2.5 复杂,访问速度有严格要求的大型站点
复杂的定义:同上。
访问速度要求:停留时间不长,用户对访问速度的心理预期较高。
但是如果用户把网站当作工具使用,需要你很快给出响应的时候,这样的实现就不好了。后续几个部分我们介绍下这些优化的抉择。
3. 域名的选择
域名对访问速度的影响具有两面性:域名多,域名解析和建立连接的时间就多;域名少,下载并发度又不够。
https 下重建连接的时间成本比 http 更高,对于上面提到的简单的大型站点,可以用少量域名就能满足需求,对于百度这样富展现样式较多的搜索引擎来说,页面可能展示的资源种类太多。而不同类型的资源又是由不同的域名 (不同的产品或者第三方产品) 提供的服务,换一个词搜索就可能需要重新建立一些资源的 ssl 链接,会让用户感受到卡顿。
如果将域名限制在有限的范围,维持和这些域名的连接,合并一些数据,加上有 spdy、http2.0 来保证并发,是可以满足我们的需求的。
4. 连接复用
连接复用率可以分为 tcp 和 ssl 等不同的层面,需要分开进行分析和统计。
4.1 连接复用的意义
HTTP 协议 (RFC2616) 规定一个域名最多不能建立超过 2 个的 TCP 连接。但是随着互联网的发展,一张网页的元素越来越多,传输内容越来越大,一个域名 2 个连接的限制已经远远不能满足现在网页加载速度的需求。
目前已经没有浏览器遵守这个规定,各浏览器针对单域名建立的 TCP 连接数如下:
浏览器 | 连接数 |
Firefox 2 | 2 |
Firefox 3+ | 6 |
Chrome | 6 |
Ie10 | 8 |
IE8 | 6 |
Safari 5 | 6 |
Opera 12 | 6 |
表格 1 浏览器单域名建立的最大并发连接数
从上表看出,单个域名的连接数基本上是 6 个。所以只能通过增加域名的方式来增加并发连接数。在 HTTP 场景下,这样的方式没有什么问题。但是在 HTTPS 连接下,由于 TLS 连接建立的成本比较高,增加并发连接数本身就会带来较大的延迟,所以对域名数需要一个谨慎的控制。
特别是 HTTP2 即将大规模应用,而 HTTP2 的最大特性就是多路复用,使用多个域名和多个连接无法有效发挥多路复用和压缩的特性。
那 HTTPS 协议下,一张网页到底该有多少域名呢?这个其实没有定论,取决于网页需要加载元素个数。
4.2 预建连接
既然从协议角度无法减少握手对速度的影响,那能不能提前建立连接,减少用户可以感知的握手延迟呢?当然是可以的。思路就是预判当前用户的下一个访问 URL,提前建立连接,当用户发起真实请求时,TCP 及 TLS 握手都已经完成,只需要在连接上发送应用层数据即可。
最简单有效的方式就是在主域下对连接进行预建,可以通过请求一些静态资源的方式。但是这样还是不容易做到极致,因为使用哪个连接,并发多少还是浏览器控制的。例如你对 a 域名请求一个图片,浏览器建立了两个连接,再请求一张图片的时候,浏览器很大概率能够复用连接,但是当 a 域名需要加载 10 个图片的时候,浏览器很可能就会新建连接了。
4.3 Spdy 的影响
Spdy 对于连接复用率的提升非常有效,因为它能支持连接上的并发请求,所以浏览器会尽量在这个链接上保持复用。
4.4 其它
也可以尝试一些其他发方法,让浏览器在访问你的网站之前就建立过 https 连接,这样 session 能够复用。HSTS 也能有效的减少跳转时间,可惜对于复杂的网站来说,开启需要考虑清楚很多问题。
5. 优化的效果
从百度的优化经验来看看,如果不开启 HSTS,用户在浏览器直接访问主域名,再通过 302 跳转到 HTTPS。增加的时间平均会有 400ms+,其中 302 跳转和 ssl 握手的因素各占一半。但是对于后续的请求,我们做到了对绝大部分用户几乎无感知。
这 400ms+ 还有很多可以优化的空间,我们会持续优化用户的体验。
HTTPS 迁移遇到的一些常见问题
1. 传递 Referrer
我们可以把自己的网站替换为 https,但是一般的站点都有外链,要让外链都 https 目前还不太现实。很多网站需要从 referrer 中判断流量来源,因此对于搜索引擎这样的网站来说,referer 的传递还是比较重要的。如果不做任何设置,你会发现在 https 站点中点击外链并没有将 referrer 带入到 http 请求的头部中 (http://tools.ietf.org/html/rfc7231#section-5.5.2)。现代的浏览器可以用 meta 标签来传递 refer。 (http://w3c.github.io/webappsec/specs/referrer-policy)
<meta name=”referrer” content=”always”> 传递完整的 url
<meta name=”referrer” content=”origin”> 只传递站点,不包含路径和参数等。
对于不支持 meta 传递 referrer 的浏览器,例如 IE8, 我们怎么办呢?
可以采用再次跳转的方法,既然 HTTPS 下不能给 HTTP 传递 referer,我们可以先从 HTTPS 访问一个可控的 http 站点,把需要传递的内容放到这个 http 站点的 url 中,然后再跳转到目标地址。
2. form 提交
有时需要将 form 提交到第三方站点,而第三方站点又是 http 的地址,浏览器会有不安全的警告。可以和 referrer 的跳转传递采取相似的逻辑。
但是这样对 referer 和 form 等内容的方案,并不是完美的解决方法,因为这样还是增加了不安全的因素(劫持,隐私泄露等 )。理想情况需要用户升级符合最新规范的浏览器,以及推进更多的站点迁移至 https。
3. 视频播放
简单来说,如果你使用 http 的协议来播放视频,那么浏览器仍然会有不安全的提示。所以你有两种选择,1 让视频源提供 https。2 使用非 http 的协议,如 rtmp 协议。
4. 用户异常
在 https 迁移的过程中,也会有不少热心的用户向我们反馈遇到的各种问题。
常见的有以下的一些情况:
1 用户的系统时间设置错误,导致提示证书过期。
2 用户使用 fiddler 等代理进行调试,但是没有添加这些软件的根证书,导致提示证书非法。
3 用户使用的 Dns 为公共 dns 或者跨网设置 dns,一些请求被运营商作为跨网流量拦截。
4 连通性有问题,我们发现一个小运营商的 https 失败率奇高,又没法联系到他们,只能不对他们进行 https 的转换。
5 慢。有时由于网络环境的因素,用户打开其他网站也慢,ping 哪个网站都要 500-2000ms,这时 https 自然也会很慢。
对于复杂的大型网站来说,HTTPS 的部署有很多工作要完成。面对困难和挑战,有充足的动力支持着我们前进:https 上线后,劫持等原因导致的用户功能异常,隐私泄露的反馈大幅减少。
热心的用户经常会向我们反馈遇到的各种问题。在以前,有时即使我们确定了是劫持的问题,能够解决问题的方法也非常有限。每当这种时候,自己总会产生一些无力感。
HTTPS 的全站部署,给我们提供了能解决大部分问题的选项。能让一个做技术的人看到自己的努力解决了用户的问题,这就是最棒的收获。
HTTPS 没有想像中难用和可怕,只是没有经过优化。与大家共勉。
版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。
-END-