但行好事 莫问前程
前言🎀
可能很多人跟我一样,作为一个非科班出身的前端开发,对于 计算机网络 相关的知识非常头疼。
而 HTTPS 作为一种重要的网络通信协议,知识点多 且充满关联性,很难死记硬背。
经历过数次 【记了忘 - 忘了记】😿😿,索性趁着本次复习,梳理出自己的理解,希望对同样有困难的人有所帮助。
本文仅作为一个前端开发者简单的分享个人见解,不过多讨论繁琐、标准的答案,灵活理解 > 死记硬背。
推荐一个学习网站 《图解网络介绍》xiaolincoding.com/network/ ,感谢大佬的无私分享。
简介
例如上课时 小明和小红通过纸条进行对话,但需要同学帮忙传递,会出现以下场景:
约好放学回家的小红在校门口左等右等没等到小明,在拒绝了舔狗小王后,决定去食堂吃饭,却看到了小明、小美一起吃饭的一幕😭. . .
玩笑之外,我们不难发现,上述流程充满了风险:
- 纸条上的明文数据,随时都可能被监听泄漏
- 收到纸条时,来源无法确定
- 纸条内容可以随意被篡改,甚至直接被替换
转到计算机网络视角,客户端与服务端之间的 HTTP 通信存在同样的安全问题:
- 窃听风险:数据以明文形式暴露在网络链路中,容易被中间人窃听或篡改
- 冒充风险:接收方不会验证通信方的身份,无法确定是否在跟正确的目标通信
- 篡改风险:通信不提供数据完整性保护,攻击者可以在传输过程中篡改数据
而 HTTPS 就是用以解决上述安全问题的 超文本传输安全协议,接下来我们看看它是怎么实现的。
TLS
面对上述的安全问题,HTTPS 选择在 HTTP 与 TCP 层之间加入 安全传输层协议(TLS)。
我们可以简单的理解为:HTTPS = HTTP + SSL/TLS
TLS 是由 SSL 演变而来,很多时候我们谈论 SSL 时指的是 TLS
而 TLS 是如何解决 HTTP 的风险的呢?
TLS 主要提供三个关键的功能,最终目的是建立一个安全的通信通道:
- 数据加密
- 身份认证
- 校验完整性
加密
加密 便是一种将数据从
明文(未加密)转换为密文(加密)的方法,明文信息被隐匿起来,在缺少特殊信息时不可读。
例如小明和小红约定好了一个字典,某个数字映射某个字,"放学一起去食堂吃饭" -> "3.1.5.6 ..."。没有字典的人拿到这串数字只会一头雾水。这样就解决了 窃听风险。
而 HTTPS 便是通过 安全传输层协议(TLS) 在数据传输前,对数据进行加密。
TLS 是如何加密的? 我们需要了解两种常用的加密方式: 对称加密 & 非对称加密。
对称加密
一个密钥可以同时用作信息的加密和解密,这种加密方法称为 对称加密。
密钥 是密码和明码之间的对应替代关系,如以00、01、02、03代替字母A、B、C、D,那么00译成A、01译成B、02译成C、03译成D就是密钥。
通信双方使用同一把密钥,无论是 客户端 -> 服务端 还是 服务端 -> 客户端,都有加密/解密能力。
但对称加密存在一个很关键的问题是:通信双方怎么拥有同一把钥匙?
我们可能想到以下两种方法:
- 事先商量好密钥存在本地
- 发起通信时将密钥发送给对方
那么问题又来了:
- 密钥管理问题:客户端与服务端之间是
N对M的关系,密钥的数量是不确定的,密钥管理十分困难 - 密钥交换问题:网络已经是不安全的了,如果密钥被拦截,那么安全问题还是存在
所以虽然对称加密很简便,但并不能解决传输问题。
对称加密具有 计算量小、加密速度快、加密效率高 的优点
非对称加密
加密密钥和解密密钥不相同,一个公开,一个保密。公开的称为公钥,保密称为私钥,这种加密方法称为 非对称加密。
公钥是一把钥匙A(解锁 锁B) 也是一把锁(锁A),加密后的数据是不可逆的 或者说很难逆转。
私钥是一把钥匙B(解锁 锁A)也是一把锁(锁B),即 使用公钥加密的数据 只有私钥能解出。
而非对称加密的问题更加明显:服务端 -> 客户端 的数据是不安全的,私钥加密的响应数据可以被公开的公钥解出,即只能保证单向的安全。
我们可能想到那使用两组非对称密钥?即
- 客户端有 公钥A 私钥A,服务端有 公钥B 私钥B
- 客户端 与 服务端 交换公钥
- 客户端 -> 服务端 使用公钥B加密,服务端 接收数据用私钥B解密
- 服务端 -> 客户端 使用公钥A加密,客户端 接收数据用私钥A解密
问题似乎解决了,但非对称加密需要进行复杂的数学计算,加密、解密速度相对于对称加密要慢得多。
在追求响应速度的前提下,两组非对称加密并不是最优解。
混合加密
我们简单整理两种加密的优缺点:
- 对称加密: 优点 - 速度快、效率高,缺点 - 密钥管理困难、无法安全交换
- 非对称加密: 优点 - 保证单向安全,缺点 - 加密效率低
那我们是否可以利用两种加密 取长补短?
- 建立通信时,客户端生成一个
对称密钥X - 服务端将自己的
非对称公钥A发送给客户端 - 客户端使用
非对称公钥A对对称密钥X进行加密 生成密文C(内含明文-密钥X) - 服务端接收到
密文C(内含明文-密钥X),使用非对称私钥A取出密文中的对称密钥X - 以上过程 安全的完成了密钥的交换
- 其中
对称密钥X也称作会话密钥,之后的通信都通过只有双方知道的会话密钥进行 - 因为
会话密钥的本质是对称加密所以 加密/解密速度较快
上述的思路便是 混合加密,TLS 以此建立安全的连接。
非对称加密中使用的主要算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等
选用不同的非对称加密算法(也称公钥加密算法),TLS 的握手过程可能会有一些区别,本文从经典的 RSA加密算法 进行讲述。
解决了 窃听风险,我们还有 冒充风险 和 篡改风险 需要解决。
身份认证
使用非对称密钥时,安全是没有保障的,中间人可以拦截服务端公钥,并对公钥进行篡改。
我们模拟以下场景:
假设服务端预存了一套 公钥A+ 和 私钥A-
中间人也有一套 公钥B+ 和 私钥B-
- 客户端请求后,服务端返回
公钥A+ - 中间人拦截到
公钥A+,返回客户端自己的公钥B+
- 客户端生成
对称密钥X并使用公钥B+加密,然后返回给服务端 - 中间人拦截到客户端数据,并使用
私钥B-解密拿到对称密钥X - 中间人使用拦截到的
公钥A+加密对称密钥X,然后发送给服务端
- 服务端接收到中间人数据,使用
私钥A-解密得到对称密钥X - 此后加密通信内容都会被中间人窃听,且服务端和客户端还认为正在安全通信
上述的场景就是 冒充风险。
问题核心是:客户端直接使用了被替换的 公钥B+。
客户端需要校验公钥持有者(服务端)的身份,防止第三方冒充,即进行 身份认证。
服务端为了证明自己的身份,会发送「Server Certificate」给客户端,这个消息里含有 数字证书(CA证书)。
数字证书
数字证书,通常包含了 【公钥、数字签名、持有者信息、证书有效期...】等内容。
它就是服务端的"身份证",通过它可以确定服务端是否合法、可信。
如何获得数字证书?
就像成年后向公安局申请身份证一样。
服务端的证书都 需要向CA(Certificate Authority,证书认证机构)申请。
CA 就是网络世界里的公安局、公证中心,具有极高的可信度,所以由它来给各个公钥签名。
信任的一方签发的证书,那必然证书也是被信任的。
公钥都能被拦截篡改,同样,传递过来的证书也是不可信的,又该如何校验数字证书?
就像公司文件只有领导签字才有效一样。
CA机构也会对每个数字证书添加"防伪标识"——数字签名。
数字签名
CA机构会使用存在自身的 非对称私钥 对 证书 进行数字签名,签名流程如下:
- CA 会把持有者的【公钥、用途、颁发者、有效时间等明文信息】打包,并进行 Hash 计算,得到
数据摘要 - 然后 CA 使用自己的私钥加密这份
数据摘要,生成证书签名(Certificate Signature)也称 数字签名 - 将
数字签名添加在文件证书上,结合证书明文数据+数字签名形成数字证书
客户端接收到数字证书后,校验流程如下:
- 客户端使用同样的Hash算法,从
证书明文数据中计算出 Hash 值H1 - 使用 CA 的公钥解密
数字签名内容,得到一个 Hash 值H2 - 比较
H1和H2,相同-证书可信,不相同-证书不可信
Q:CA公钥从哪里获取?
A:能颁发证书的CA机构可不多,因此对应的CA公钥也不多,CA公钥已事先注入到浏览器或操作系统里
Q:为什么对比 H1 和 H2,就能判断数字证书是否未被篡改?
A:数字签名可以看做一个加密副本,如果证书明文被篡改(例如明文公钥被替换),明文信息计算出的 H1 与 加密副本解密出的 H2 无法对齐,客户端可认为证书是无效的。
Q:如果证书的数字签名被篡改?
A:中间人没有CA私钥 也没法正确的修改数字签名,胡编乱造只会导致 H1 与 H2 无法对齐。
Q:为什么CA要hash一次明文数据,而不是直接将明文加密?
A:原文内容过长,hash之后可以让数据变短,减少传输成本。
RSA
对于RSA其实我们只用知道——它利用各种数学理论生成了一对数字,利用一个数字加密的数据 只有另一个数字能解密,即 生成一对非对称密钥。
下面简述大致流程 可以跳过。
| 步骤 | 说明 | 描述 | 备注 |
|---|---|---|---|
| 1 | 选择质数 | p、q | - |
| 2 | 计算公共模数 | N = p * q | - |
| 3 | 欧拉函数 | φ(N) = (p − 1) × (q − 1) | 小于N且与N互质的正整数的个数 |
| 4 | 选出公钥E | 1 < E < φ(N) | e 与 φ(N) 互质 |
| 5 | 计算私钥D | D × E mod φ(N) = 1 | 利用费马小定理 |
密钥用法如下:
- 公钥由 N 和 E 组成(E, N),私钥由 D 和 N 组成(D, N)。
- 加密:给定原文M,使用公钥(E, N)加密明文得到密文C
- 解密:使用私钥(D, N)对密文C进行解密,还原出原文M
该流程具有不可逆性,即使知道了公钥和密文,也很难解密出明文来。
例如 已知:公钥 e(5, 7) 与 密文 4,原文 M 未知
M^5 mod 7 = 4得M = 2很好计算- 但当模数很大时
M^5 mod 56374677648 = 4这个M基本无解。
非对称密钥的生成过程发生在服务端,即保存私钥的地方,你可以通过指令生成一个:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
RSA因为不支持前向保密的原因,在TLS1.3中已被遗弃。当前多数网站使用的是ECDHE密钥协商算法
但不管是RSA 还是椭圆曲线密码,它们的实现过程均使用了 取模运算
TLS握手
最后看看完整的 TLS 加密流程:
- 第一次握手:
Client Hello: 客户端发送随机数(server_random)、提供可选的 TLS版本 和 加密套件
- 第二次握手:
Server Hello: 服务端发送随机数(client_random)、确认TLS版本 和 加密套件Server Certificate: 为证明身份,服务端发送数字证书(明文信息 + 数字签名)
- 第三次握手:
- 客户端通过CA公钥验证数字证书,取得RSA公钥
Client Key Exchange:生成随机数(pre-master)并用RSA公钥加密,发送给服务端- 客户端结合三个随机数(Client Random、Server Random、pre-master)生成会话密钥(Master Secret)
Change Cipher Spec:告诉服务端开始使用加密方式发送消息Encrypted Handshake Message(Finishd):对之前所有发送的数据进行摘要,再用会话密钥加密后发送
- 第四次握手:
- 服务端使用RSA私钥解密得到随机数(pre-master)
- 客户端结合三个随机数,得到与客户端相同的会话密钥(Master Secret)
- 同样发送
Change Cipher Spec和Encrypted Handshake Message消息
Q:Encrypted Handshake Message 有什么作用?
A:客户端/服务端 接收后即可验证加密通信「是否可用」和「之前握手信息是否有被中途篡改过」
Q:为什么需要两个随机数 不直接加密 pre-master 发送?
A:只有单个 pre-master 随机性不足,多次随机的情况下有可能出来的密钥是一样的。但如果再引入两个随机数,就能大大增加"会话密钥"的随机程度,从而保证每次HTTPS通信用的会话密钥都是不同的。
更多
大数取模是否无法破解? TLS1.3相比TLS1.2有什么变化? RSA有什么缺点 为什么会被遗弃? HTTPS还有什么优化的地方? ...
还有很多相关知识等着我们去探究。
总结
传统 HTTP 网络的传输存在安全问题: 窃听风险、篡改风险、冒充风险。
HTTPS - 超文本传输安全协议 就是用以解决上述安全问题的协议,HTTPS = HTTP + SSL/TLS。
TLS - 安全传输层协议 提供了三个关键的功能:
- 加密 - 混合加密:利用非对称加密安全的传输对称密钥,利用对称密钥高效的加密明文数据
- 身份认证 - CA证书:CA机构提供的身份证明,包含服务器公钥、持有者信息、数字签名 . . .
- 完整性校验 - 数字签名:摘要算法提取证书信息,然后使用CA私钥加密,只有CA公钥能解出
RSA 实现非对称加密的原理是 大数取模的运算不可逆。
TCP三次握手之后,进行TLS四次握手,简要过程如下:
- 客户端向服务端索要非对称加密的公钥,并验证对方身份
- 双方协商生成对称加密的“会话密钥”
- 双方使用“会话密钥”进行对称加密通信
参考
xiaolincoding.com/network/2_h…
结语🎉
不要光看不实践哦,希望本文能对你有所帮助。
持续更新前端知识,脚踏实地不水文,真的不关注一下吗~
写作不易,如果有收获还望 点赞+收藏 🌹
才疏学浅,如有问题或建议还望指教!