从“v我50”到“疯狂星期四”:HTTPS如何用47天寿命的证书挡住中间人

最近看到一篇IT之家的新闻,《SSL/TLS证书最长有效期将缩短至47天》

以前 SSL/TLS 证书最长有效期可以长达 8 年,不过经过几次调整后当前证书有效期最长为 398 天约 13 个月,也就是说无论如何开发者和企业都必须在 13 个月左右更新一次数字证书。

而苹果提交的 SC-081v3 草案目前已经获得行业组织的同意,简单来说最终 SSL/TLS 证书有效期将被缩短至 47 天,整个过程将循序渐进的推广,即逐步缩短有效期直到达成缩短至 47 天。

随着SSL/TLS证书有效期的逐步缩减,也意味着CA/Browser Forum(证书颁发机构/浏览器论坛)对安全性日益关注。试想,在公共 Wi-Fi 下打开手机银行应用,准备转账时,账户余额、密码等敏感信息却可能被不法分子拦截篡改,导致资金被盗。这并非骇人听闻,而是网络 "中间人攻击" 常见场景。幸运的是,HTTPS 协议作为网络安全重要防线,能有效抵御此类威胁。那么HTTPS协议是如何运作的,证书验证过程又是怎么样的呢?这篇文章带你来一探究竟。

一、为什么需要加密

HTTP协议在设计之初并未考虑安全性,所有数据以明文形式在网络中传输。这种设计在开放、可信的早期互联网环境中尚可接受,但在当今复杂的网络环境下,其缺陷暴露无遗:

明文数据会经过中间代理服务器、路由器、wifi热点、通信服务运营商等多个物理节点,如果信息在传输过程中被劫持,传输的内容就完全暴露了。劫持者还可以篡改传输的信息且不被双方察觉,这就是中间人攻击。所以我们才需要对信息进行加密。

二、常见的加密方式

加密方式主要分为两大类,对称加密和非对称加密

2.1 对称加密

加密和解密双方使用相同的密钥来进行数据的加密和解密操作。常见的对称加密算法有 AES(高级加密标准)、DES(数据加密标准)等。

以 AES算法 为例,它将明文数据按照一定的块大小(通常是 128 位)进行分组,然后通过多轮复杂的运算(包括字节替换、行移位、列混淆和轮密钥加等操作),最终将明文转换为密文,也可使用同样的方法将密文转换为明文。在这个过程中,同一个密钥既用于将明文加密成密文,也用于将密文解密回明文。

2.2 非对称加密

非对称加密则涉及两个不同的密钥,即公钥(Public Key)和私钥(Secret Key)。公钥可以无限制对外公开,而私钥则要严格保密。加密时使用公钥加密的数据,只有对应的私钥才能解密;反过来,用私钥加密的数据,也只有对应的公钥才能解密。常见的非对称加密算法有RSA(Rivest-Shamir-Adleman)、ECC(椭圆曲线密码学)等

以 RSA 算法为例,它是基于大整数因数分解难题的非对称加密算法。在加密时,将明文数据转化为大整数,然后用接收方的公钥(包含两个大质数的乘积等信息)按照一定的数学规则进行运算,得到密文。而解密时,只有使用与该公钥配对的私钥(包含这两个大质数等关键信息),才能通过逆向的数学运算解密回明文。

三、HTTPS证书验证过程

3.1 明文通信

首先从最简单明文通信开始。存在一个服务端Server和一个客户端Client。这里跳过TCP/IP握手过程,直接进入到ESTABLISHED状态。在不进行任何信息加密的情况下,通信过程可参考下图

arduino 复制代码
1.客户端Client向服务端Server明文发送信息【v我50】
2.Server收到消息后向Client明文回复消息【疯狂星期四】
3.Client喜笑颜开

如果整个通信过程Client和Server仅通过一根网线直接连接的话,那么通信的安全性是完全没有问题的。但是真实的通信链路会经过中间代理服务器、路由器、wifi热点、通信服务运营商等多个物理节点,如果信息在传输过程中被劫持,传输的内容就完全暴露了。劫持者还可以篡改传输的信息且不被双方察觉,这就是中间人攻击(MITM)。通信过程可参考下图

arduino 复制代码
1.客户端Client向服务端Server明文发送信息【v我50】
2.中间人MiddleMan劫持到消息后,篡改为【转我50】
3.Server收到消息后向Client明文回复消息【我们不熟】
4.MiddleMan劫持到消息后没有篡改消息,直接回复给了Client
5.Client留下了伤心的泪水

为了防止MiddleMan劫持后可以看到消息内容,可以考虑通过加密的方式进行通信,先从简单的对称加密通信开始尝试

3.2 对称加密通信

对称加密中加密的密钥和解密的密钥是一致的。这里使用E1来表示密钥。假设Client和Server已经在保密的情况下分别获取到了E1。通信过程可参考下图

arduino 复制代码
1.客户端Client使用密钥E1加密明文【v我50】生成密文【U2FsdGVkX1】
2.Client向服务端Server发送密文【U2FsdGVkX1】
3.Server接收到【U2FsdGVkX1】后使用E1进行解密得到【v我50】
4.Server使用E1加密明文【疯狂星期四】生成密文【S6Vk01J1u】
5.Server向Client发送密文【S6Vk01J1u】
6.Client接收到【S6Vk01J1u】并使用E1进行解密得到【疯狂星期四】
7.Client喜笑颜开

这个通信过程看起来足够安全,但是还记得我们的前提吗,Client和Server已经在保密的情况下分别获取到了E1。

如何做到保密呢。是否可以提前存储在Client和Server上。在实际的网络环境中,会有很多台客户端C2、C3或很多台S2、S3等。这就要考虑不同的Client和Server是否都使用E1。如果是,那么MiddleMan也可以拿到E1,如果不是,双方就要存储全世界所有的密钥,即使很多Server我们终生也不会访问。而且又涉及到密钥更新和废除的问题。

那么可以通过网络通信交换E1吗,其实这样和明文传输没有实质区别。通信过程可参考下图

arduino 复制代码
1.客户端Client向服务端Server询问【使用的对称密钥是什么】
2.中间人MiddleMan劫持到消息后没有篡改消息,发送给了Server
3.Server收到消息后明文回复消息【就用E1吧】
4.MiddleMan劫持到消息,保存下E1后,将消息【就用E1吧】明文回复给了Client
5.Client使用E1加密消息【v我50】,生成密文【U2FsdGVkX1】,发送给Server
6.MiddleMan劫持到消息,使用E1解密得到【v我50】
7.MiddleMan篡改消息为【转我50】并使用E1加密,生成密文【eG55ddqk】,发送给Server
8.Server收到消息,使用E1解密得到【转我50】,使用E1加密消息【我们不熟】,生成密文【S6Vk01J1u】,回复给Client
9.MiddleMan劫持到消息,使用E1解密得到【我们不熟】,没有进行篡改发送给了Client
10.Client收到消息【S6Vk01J1u】,使用E1解密得到【我们不熟】
11.Client留下了伤心的泪水

这个通信过程可以发现仅使用对称加密是无法解决通信安全性的问题的,那么使用非对称加密呢。

3.3 非对称加密通信

由于仅使用对称加密是无法解决通信安全性的问题,因此考虑使用非对称加密。非对称加密包含一组密钥,公钥和私钥。使用公钥加密的数据,只有对应的私钥才能解密;反过来,使用私钥加密的数据,也只有对应的公钥才能解密。公钥可以无限制对外公开,而私钥则要严格保密。假设服务端拥有公钥PK1和私钥SK1。通信过程可参考下图

arduino 复制代码
1.客户端Client向服务端Server询问【你的公钥是什么】
2.Server收到消息后明文回复消息【我的公钥是:PK1】
3.Client使用公钥PK1加密明文【v我50】生成密文【U2FsdGVkX1】
4.Client向服务端Server发送密文【U2FsdGVkX1】
5.Server接收到【U2FsdGVkX1】后使用私钥SK1进行解密得到【v我50】
6.Server使用SK1加密明文【疯狂星期四】生成密文【S6Vk01J1u】
7.Server向Client发送密文【S6Vk01J1u】
8.Client接收到【S6Vk01J1u】并使用PK1进行解密得到【疯狂星期四】
9.Client喜笑颜开

由于公钥是无限制公开的,那么中间人也可以正常拿到公钥PK1,此时中间人攻击过程可参考下图:

arduino 复制代码
1.客户端Client向服务端Server询问【你的公钥是什么】
2.中间人MiddleMan劫持到消息后没有篡改消息,发送给了Server
3.Server收到消息后明文回复消息【我的公钥是:PK1】
4.MiddleMan劫持到消息,保存下PK1后,将消息【我的公钥是:PK1】明文回复给了Client
5.Client使用PK1加密消息【v我50】,生成密文【U2FsdGVkX1】,发送给Server
6.MiddleMan劫持到消息【U2FsdGVkX1】,由于没有Server的私钥SK1,所以无法解密消息,只能将消息发送给Server
7.Server收到消息,使用SK1解密得到【v我50】,Server使用SK1加密明文【疯狂星期四】生成密文【S6Vk01J1u】
8.Server向Client发送密文【S6Vk01J1u】
9.MiddleMan劫持到消息,使用PK1解密消息得到【疯狂星期四】,不过由于没有SK1,无法对消息进行篡改,便将消息发送给了Client
10.Client接收到【S6Vk01J1u】并使用PK1进行解密得到【疯狂星期四】
11.Client喜笑颜开

这种方式虽然MiddleMan无法篡改信息,也无法知道Client向Server发送的信息内容。但是可以知道来自Server的消息内容。所以这种通信模式仅可以保证Client向Server单向通信是安全的(当然这种模式还有其他更严重的漏洞,在这里先不展开)。那么这是不是可以利用这一特点。Client生成对称加密密钥安全的传递给Server,之后双方使用对称加密密钥进行加解密。这种通信方式称为混合加密通信。

3.4 混合加密通信

混合解密通信是先通过非对称加密协商出对称加密密钥,之后通过对称加密方式进行实时通信的过程。这样即使中间人劫取了信息,由于无法获取到对称加密密钥,所以也无法对信息进行加解密。假设协商的对称加密密钥为E1,通信过程可参考下图

arduino 复制代码
1.客户端Client向服务端Server询问【你的公钥是什么】
2.中间人MiddleMan劫持到消息后没有篡改消息,发送给了Server
3.Server收到消息后明文回复消息【我的公钥是:PK1】
4.MiddleMan劫持到消息,保存下PK1后,将消息【我的公钥是:PK1】明文回复给了Client
5.Client使用PK1加密已经准备好的对称密钥【E1】,生成密文【pTyLGTddEr】,发送给Server
6.MiddleMan劫持到消息【pTyLGTddEr】,由于没有Server的私钥SK1,所以无法解密消息,只能将消息发送给Server
7.Server收到消息,使用SK1解密得到【E1】,Server使用E1加密明文【Finished】生成密文【BFgENlNcc】
8.Server向Client发送密文【BFgENlNcc】
9.MiddleMan劫持到消息,由于没有对称加密的密钥E1,所以无法解密消息,便将消息发送给了Client
10.Client接收到【BFgENlNcc】并使用【E1】解密得到【Finished】,便知道Server已经准备好了
11.Client使用E1加密消息【v我50】得到密文【U2FsdGVkX1】,而后发送给Server
12.MiddleMan劫持到消息,由于没有对称加密的密钥E1,所以无法解密消息,便将消息发送给了Server
13.Server接收到【U2FsdGVkX1】后使用E1解密得到明文【v我50】
14.Server使用E1加密消息【疯狂星期四】得到密文【S6Vk01J1u】,发送给Client
15.MiddleMan劫持到消息,由于没有对称加密的密钥E1,所以无法解密消息,便将消息发送给了Client
16.Client收到消息【S6Vk01J1u】,使用E1解密得到【疯狂星期四】
17.Client喜笑颜开

在这种通信模式下,看起来已经足够安全了,但是还记得在上文提到的这种模式还有其他更严重的漏洞吗。现在一起来分析下中间人还能通过什么方式获取信息呢。假设中间人拥有自己的公钥PK2和私钥SK2,通信过程可参考下图

arduino 复制代码
1.客户端Client向服务端Server询问【你的公钥是什么】
2.中间人MiddleMan劫持到消息后没有篡改消息,发送给了Server
3.Server收到消息后明文回复消息【我的公钥是:PK1】
4.MiddleMan劫持到消息,保存下PK1后,将PK1篡改成自己的公钥PK2,明文回复给【我的公钥是:PK2】Client
5.Client使用PK2加密已经准备好的对称密钥【E1】,生成密文【pTyLGTddEr】,发送给Server
6.MiddleMan劫持到消息【pTyLGTddEr】,使用自己的私钥SK2解密得到E1
7.保存下E1后,使用PK1加密E1得到密文【2FsdGVkX1】,发送给Server
8.Server收到消息,使用SK1解密得到【E1】,Server使用E1加密明文【Finished】生成密文【BFgENlNcc】
9.Server向Client发送密文【BFgENlNcc】
10.MiddleMan劫持到消息,使用E1解密得到【Finished】,没有篡改消息,便将消息发送给了Client
11.Client接收到【BFgENlNcc】并使用【E1】解密得到【Finished】,便认为Server已经准备好了
12.Client使用E1加密消息【v我50】得到密文【U2FsdGVkX1】,而后发送给Server
13.MiddleMan劫持到消息,使用E1解密消息得到【v我50】
14.MiddleMan将消息【v我50】篡改成【转我50】并使用E1加密得到密文【eG55ddqk】,将消息发送给了Server
15.Server接收到【eG55ddqk】后使用E1解密得到明文【转我50】
16.Server使用E1加密消息【我们不熟】得到密文【S6Vk01J1u】,发送给Client
17.MiddleMan劫持到消息,没有篡改消息,便将消息发送给了Client
18.Client收到消息【S6Vk01J1u】,使用E1解密得到【我们不熟】
19.Client留下了伤心的泪水

中间人通过一招狸猫换太子劫取到了全部的信息。而问题的根源就在于Client无法验证Server返回证书的身份,也就只能无条件相信证书的合法性。那么是否可以像指纹一样每个人(证书)都有一个特定的纹理(数字签名)。这样Client就可以像验证指纹一样验证证书的合法性了。这也就是CA机构(证书授权机构)的核心作用了。

四、CA(Certificate Authority)证书授权机构

简单介绍下CA机构的发展史。1994年网景公司 (Netscape)推出了SSL1.0。随后, SSL 2.0 和 SSL 3.0 相继发布。1999年, IETF (国际互联网工程任务组)将SSL 3.0改进后标准化为 TLS 1.0 。为了便于协同制订SSL/TLS证书等安全规范。CA/Browser Forum(CA/浏览器论坛)于2005年正式成立。

那么证书授权机构是如何解决证书网络传播的身份不确定问题的呢。所有合规的企业和具有完全民事行为能力的个人都可以申请CA数字证书。CA数字证书主要包含三部分。证书明文信息T(包含公钥、域名、企业信息)、摘要算法M和数字签名S。以百度的公开数字证书为例。如下图:

那么数字证书是如何生成的呢,可参考下图。

r 复制代码
1.证书明文信息T包含公钥、域名、企业信息
2.通过协商好的摘要算法M进行散列得到Hash值
3.签发者(CA机构)使用私钥对Hash值进行加密得到数字签名S(证书指纹)
4.数字签名S和证书明文信息T组合起来,生成CA证书

CA机构认证的证书就安全了吗,可以从下面两个方向进行讨论。

4.1 中间人有可能篡改该证书吗

假设中间人篡改了证书的原文,由于他没有CA机构的私钥,所以无法得到此时加密后签名,无法相应地篡改签名。Client收到该证书后会发现原文和签名解密后的值不一致,则说明证书已被篡改,证书不可信,从而终止向Server传输信息,防止信息泄露给中间人。

既然不可能篡改,那整个证书被掉包呢?

4.2 中间人有可能把证书掉包吗

假设有另一个ClientB也拿到了CA机构认证的证书,它想劫持ClientA的信息。于是它成为中间人拦截到了Sever传给ClientA的证书,然后替换成自己的证书,传给ClientA。之后ClientA就会错误地拿到ClientB的证书里的公钥了,那么这里就会导致上文"中间人攻击"那里提到的漏洞吗?

其实这并不会发生,因为证书里包含了Server的信息,包括域名、企业信息等。计算机把证书里的域名与自己请求的域名比对一下就知道有没有被掉包了。

五、完整的证书验证过程

经过上述的介绍,HTTPS证书的验证过程已经基本介绍完了,而在实际通信过程中对称加密的密钥E1并不是由Client生成然后传输给Server的。而是通过SSL/TLS四次握手协商产生的。完整的协商和通信流程可参考下图

arduino 复制代码
1.客户端Client向服务端Server询问【你的CA证书是什么】,携带支持的TLS协议版本、加密套件和生成的随机数RandomA
2.中间人MiddleMan劫持到消息后没有篡改消息,发送给了Server
3.Server收到消息后,回复消息【我的证书是CA1】,携带选择的TLS协议版本、加密套件、生成的随机数RandomB以及Server的公钥PK1
4.MiddleMan劫持到消息后,由于没有Server的私钥SK1,无法篡改信息,而如果将CA1偷换成自己的证书CA2,则无法通过Client的根证书合法性校验,所以只能将消息原样发送给Client。
5.Client接收到消息后,首先验证证书的合法性。验证通过后会生成第三个随机数RandomC。并使用PK1进行加密生成密文【HtjyMfqw】
6.Client将密文【HtjyMfqw】发送给Server,同时使用已知的RandomA、RandomB、RandomC通过协商的加密套件生成对称密钥E1。
7.MiddleMan劫持到消息【HtjyMfqw】后,由于没有Server的私钥SK1,无法对消息进行解密,因此只能将消息原样发送给Server
8.Server收到消息后,使用SK1解密消息得到RandomC
9.Server使用已知的RandomA、RandomB、RandomC通过协商的加密套件生成对称密钥E1,而后使用E1加密消息【Finished】生成密文【BFgENlNcc】
10.Server将密文发送给Client
11.MiddleMan劫持到消息后,由于无法知道RandomC,因此也无法计算出E1,只能将消息原样发送给Client
12.Client接收到消息后,使用E1解密消息【BFgENlNcc】得到【Finished】,便知道Server准备好了
13.Client使用E1加密消息【v我50】得到密文【U2FsdGVkX1】发送给Server
14.MiddleMan劫持到消息后,由于无法知道E1,因此无法解密消息,只能将消息原样发送给Server
15.Server使用E1解密消息得到【v我50】,而后使用E1加密消息【疯狂星期四】生成密文【S6Vk01J1u】回复Client
16.MiddleMan劫持到消息后,由于无法知道E1,因此无法解密消息,只能将消息原样发送给Client
17.Client接收到消息后,使用E1解密消息【S6Vk01J1u】得到【疯狂星期四】
18.Client喜笑颜开

这样的验证过程看起来已经足够安全了,为什么还要逐步缩减证书的有效期到47天呢?实际上并没有绝对安全的加密方式,RSA加密算法的安全性依赖于大整数分解的计算复杂度。随着计算机算力的不断提升,RSA的安全性的根基也面临着更大的挑战。因此逐步降低证书有效期可以有效的提高证书安全性。

六、写在最后

本文整体的过程是基于HTTPS单向认证的。HTTPS双向认证会增加Server对Client证书的认证。由于基本过程类似,不在这里进行额外分析。

HTTPS 证书验证过程融合多种加密技术与安全机制,是现代互联网安全的基石。它不仅保护了个人隐私,也为企业数据传输提供了可靠保障。在数字化浪潮下,理解并重视 HTTPS 协议,对每一位网络参与者都至关重要。未来,HTTPS 协议将继续演进,适应日益复杂的网络环境,为网络通信安全保驾护航。

七、参考文档

转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。 关注公众号「转转技术」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于QA),更多干货实践,欢迎交流分享~

相关推荐
excel2 分钟前
JavaScript 错误处理与调试全攻略:从 try/catch 到全局兜底
前端
江城开朗的豌豆6 分钟前
点击弹窗外部自动关闭?一个useRef Hook就搞定!
前端·javascript·react.js
JarvanMo22 分钟前
跨平台开发的隐性成本
前端·后端
qq_4152162528 分钟前
html pc和移动端共用一个页面,移动端通过缩放达到适配页面,滚动飘窗
前端·html
前端小巷子44 分钟前
watch 与 computed:Vue3响应式的抉择
前端·vue.js·面试
ss2731 小时前
手写MyBatis第36弹:MyBatis执行流程中SQL命令类型解析
前端·javascript·html
IT_陈寒1 小时前
Python数据处理太慢?这5个Pandas优化技巧让速度提升300%!
前端·人工智能·后端
花落文心2 小时前
使用 html2canvas + jspdf 实现页面元素下载为pdf文件
前端·javascript·pdf
掘金安东尼2 小时前
🚀 6 行 HTML,让应用瞬间“起飞”:Speculation Rules API 全解析
前端·api·浏览器
望获linux3 小时前
【Linux基础知识系列】第一百一十篇 - 使用Nmap进行网络安全扫描
java·linux·开发语言·前端·数据库·信息可视化·php