:“兄弟,你的弹药来了!”🤝🤝🤝 面试总结·网络篇: HTTPS

2,445 阅读18分钟

本文总结了我学习 HTTP 第一遍、第二遍的知识点,以自问自答形式作为面试复习脉络,梳理看似“杂乱” 的 HTTP(方便第二遍快速深入)。

  • 如果您阅读本文相对吃力,可以参考我学习的途径进行系统的学习后再阅读本文。

  • 如果您觉得对您有帮助,可以点赞支持一下(后续还有很多类似的整理,在重构中 🙃)

  • 如果您非常期待其他的整理,可以先查阅我的仓库(虽然现在还不是很成体系,但如果你也是校招党,可能会给你全面复习的思路 🙃)

途径:图解 HTTP ➕极客时间:透视 HTTP + 三元大佬博客(太出名,地址就不贴了)

最后万分感谢神三元大佬教会我如何做笔记,如何整理知识点(虽然遥遥两地,他也不认识我 🙃)

1.HTTP 和 HTTPS 有什么区别?

HTTPS 和 HTTP 的关系

  • 协议
  • 明文/安全

HTTPS 它把 HTTP 下层的传输协议由 TCP/IP 换成了 SSL/TLS,由 “HTTP over TCP/IP” 变成了 “HTTP over SSL/TLS”,让 HTTP 运行在了安全的 SSL/TLS 协议上,收发报文不再使用 Socket API,而是调用专门的安全接口

HTTPS 是 为 HTTP 增加了四大安全特性;本身一个“非常简单”的协议,RFC 文档很小,只有短短的 7 页,里面规定了新的协议名“https”默认端口号 443,至于其他的什么请求 - 应答模式、报文结构、请求方法、URI、头字段、连接管理等等都完全沿用 HTTP,没有任何新的东西。

HTTPS 和 HTTP
HTTPS 和 HTTP

四大安全特性

机密性:是指对数据的“保密”,只能由可信的人访问,对其他人是不可见的“秘密”,简单来说就是不能让不相关的人看到不该看的东西。

对称加密和非对称加密算法

完整性:是指数据在传输过程中没有被篡改,不多也不少,“完完整整”地保持着原状。

摘要算法

身份认证:是指确认对方的真实身份,也就是“证明你真的是你”,保证消息只能发送给可信的人。

数字签名 和 CA 认证

不可否认:也叫不可抵赖,意思是不能否认已经发生过的行为,不能“说话不算数”“耍赖皮”。

数字签名

提炼

  1. 因为 HTTP 是明文传输,所以不安全,容易被黑客窃听或篡改;
  2. 通信安全必须同时具备机密性、完整性、身份认证和不可否认这四个特性;
  3. HTTPS 的语法、语义仍然是 HTTP,但把下层的协议由 TCP/IP 换成了 SSL/TLS;
  4. SSL/TLS 是信息安全领域中的权威标准,采用多种先进的加密技术保证通信安全;
  5. OpenSSL 是著名的开源密码学工具包,是 SSL/TLS 加密算法的具体实现(NodeJs 实现 https 安全层面也是使用的 OpenSSL,实现 http 使用的 http-parser);

2.说说对称加密和非对称加密的理解?

  • 加密含义
  • 对称加密:相同秘钥(快)
  • 非对称加密:公钥和私钥(慢)
  • 混合加密: TLS 通信采用的方式

加密含义

实现机密性最常用的手段是“加密”(encrypt),把消息用某种方式转换成谁也看不懂的乱码,只有掌握特殊“钥匙”的人才能再转换出原始文本。这里的“钥匙”就叫做“密钥”(key),加密前的消息叫“明文”(plain text/clear text),加密后的乱码叫“密文”(cipher text),使用密钥还原明文的过程叫“解密”(decrypt),是加密的反操作,加密解密的操作过程就是“加密算法”。

按照密钥的使用方式,加密可以分为两大类:对称加密和非对称加密。

对称加密算法

“对称加密”很好理解,就是指加密和解密时使用的密钥都是同一个,是“对称”的。只要保证了密钥的安全,那整个通信过程就可以说具有了机密性。

对称加密
对称加密

TLS 里有非常多的对称加密算法可供选择,比如 RC4、DES、3DES、AES、ChaCha20 等,但前三种算法都被认为是不安全的,通常都禁止使用,目前常用的只有 AES 和 ChaCha20。

AES 的意思是“高级加密标准”(Advanced Encryption Standard),密钥长度可以是 128、192 或 256。它是 DES 算法的替代者,安全强度很高,性能也很好,而且有的硬件还会做特殊优化,所以非常流行,是应用最广泛的对称加密算法。

ChaCha20 是 Google 设计的另一种加密算法,密钥长度固定为 256 位,纯软件运行性能要超过 AES,曾经在移动客户端上比较流行,但 ARMv8 之后也加入了 AES 硬件优化,所以现在不再具有明显的优势,但仍然算得上是一个不错的算法。

对称加密看上去好像完美地实现了机密性,但其中有一个很大的问题:如何把密钥安全地传递给对方? (“密钥交换”)

因为在对称加密算法中只要持有密钥就可以解密,如果你和网站约定的密钥在传递途中被黑客窃取,那他就可以在之后随意解密收发的数据,通信过程也就没有机密性可言.

肯定不能鸡生蛋蛋生鸡,因此有了非对称加密算法

非对称加密算法

它有两个密钥,一个叫“公钥”(public key),一个叫“私钥”(private key)。两个密钥是“不对称”的,公钥可以公开给任何人使用,而私钥必须严格保密。

公钥和私钥有个特别的“单向”性,虽然都可以用来加密解密,但公钥加密后只能用私钥解密,反过来,私钥加密后也只能用公钥解密。

非对称加密可以解决“密钥交换”的问题。网站秘密保管私钥,在网上任意分发公钥,你想要登录网站只要用公钥加密就行了,密文只能由私钥持有者才能解密。而黑客因为没有私钥,所以就无法解开密文。

很遗憾,虽然非对称加密没有“密钥交换”的问题,但因为它们都是基于复杂的数学难题,运算速度很慢,如果仅用非对称加密,虽然保证了安全,但通信速度有如乌龟,实用性就变成了零。

RSA:非对称加密的代名词,基于大数分解的数学难题; ECDHE:椭圆曲线加密算法,比 RSA 算法更安全,TLS1.3 握手是基于 ECDHE 算法,TLS1.2 可选该算法作为加密套件

提炼

  1. 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换,常用的有 AES 和 ChaCha20;
  2. 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢,常用的有 RSA 和 ECHDE;
  3. 把对称加密和非对称加密结合起来就得到了“又好又快”的混合加密,也就是 TLS 里使用的加密方式。

3. 摘要算法?和数据签名?

  • 哈希函数(哈希碰撞)
  • 摘要算法:SHA2 摘要算法
  • 数字签名:摘要算法 + 私钥
  • 实现:完整性、不可否认性、身份确定性

摘要算法

实现完整性的手段主要是摘要算法(Digest Algorithm),也就是常说的散列函数、哈希函数(Hash Function)。

你可以把摘要算法近似地理解成一种特殊的压缩算法,它能够把任意长度的数据“压缩”成固定长度、而且独一无二的摘要字符串,就好像是给这段数据生成了一个数字“指纹”。

它只有算法,没有密钥,加密后的数据无法解密,不能从摘要逆推出原文。因此只能对比两份摘要是否相同判断有无被篡改

摘要算法实际上是把数据从一个“大空间”映射到了“小空间”,所以就存在“冲突”(collision,也叫碰撞)的可能性,就如同现实中的指纹一样,可能会有两份不同的原文对应相同的摘要。好的摘要算法必须能够“抵抗冲突”,让这种可能性尽量地小。

因为摘要算法对输入具有“单向性”和“雪崩效应”,输入的微小不同会导致输出的剧烈变化,所以也被 TLS 用来生成伪随机数

你一定在日常工作中听过、或者用过 MD5(Message-Digest 5)、SHA-1(Secure Hash Algorithm 1),它们就是最常用的两个摘要算法,能够生成 16 字节和 20 字节长度的数字摘要。但这两个算法的安全强度比较低,不够安全,在 TLS 里已经被禁止使用了。目前 TLS 推荐使用的是 SHA-1 的后继者:SHA-2

SHA-2 实际上是一系列摘要算法的统称,总共有 6 种,常用的有 SHA224、SHA256、SHA384,分别能够生成 28 字节、32 字节、48 字节的摘要。

摘要算法保证了“数字摘要”和原文是完全等价的。所以,我们只要在原文后附上它的摘要,就能够保证数据的完整性

不过摘要算法不具有机密性,如果明文传输,那么黑客可以修改消息后把摘要也一起改了,网站还是鉴别不出完整性。

所以,真正的完整性必须要建立在机密性之上,在混合加密系统里用会话密钥加密消息和摘要。

数据签名

加密算法结合摘要算法,我们的通信过程可以说是比较安全了。但这里还有漏洞,就是通信的两个端点

在 TLS 里有什么东西和现实中的签名、印章很像,只能由本人持有,而其他任何人都不会有呢?只要用这个东西,就能够在数字世界里证明你的身份。

这个东西就是非对称加密里的“私钥”,使用私钥再加上摘要算法,就能够实现“数字签名”,同时实现“身份认证”和“不可否认”。

数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。

但又因为非对称加密效率太低,所以私钥只加密原文的摘要,这样运算量就小的多,而且得到的数字签名也很小,方便保管和传输。

签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解开,拿到摘要后,再比对原文验证完整性,就可以像签署文件一样证明消息确实是你发的。刚才的这两个行为也有专用术语,叫做“签名”和“验签”。

4. TLS 握手讲一下吧?

  • 握手目的:为对称加密安全交换秘钥
  • RSA 经典握手
  • ECHDE 握手:ECDHE 算法参数交换、抢跑
  • TLS1.3 握手:必须采用 ECHDE 算法,压缩为 1RTT

握手目的

实现 HTTPS 通信的机密性,在通信刚开始的时候使用非对称算法,比如 RSA、ECDHE,首先解决密钥交换的问题。然后用随机数产生对称算法使用的“会话密钥”(session key),再用公钥加密。 对方拿到密文后用私钥解密,取出会话密钥。这样,双方就实现了对称密钥的安全交换,后续就不再使用非对称加密,全都使用对称加密。

RSA 握手过程

RSA 可能是加密算法中最著名的一个,几乎可以说是非对称加密的代名词,它的安全性基于“整数分解”的数学难题,使用两个超大素数的乘积作为生成密钥的材料,想要从公钥推算出私钥是非常困难的。

RSA握手
RSA握手

大体上分为三个阶段:明文共享阶段、CA 认证阶段、生成主秘钥阶段

第一阶段:明文共享阶段

  1. 在 TCP 建立连接之后,浏览器会首先发一个“Client Hello”消息,里面有客户端的版本号、支持的密码套件,还有一个随机数(Client Random),用于后续生成会话密钥。
  2. 服务器收到“Client Hello”后,会返回一个“Server Hello”消息。把版本号对一下,也给出一个随机数(Server Random),然后从客户端的列表里选一个作为本次通信使用的密码套件以及公钥。
  3. 服务器为了证明自己的身份,就把证书也发给了客户端(Server Certificate)。
  4. Server Done

这样第一个消息往返就结束了(两个 TCP 包),结果是客户端和服务器通过明文共享了三个信息:Client Random、Server Random 和 公钥。

第二阶段:证书验证

客户端这时也拿到了服务器的证书,那这个证书是不是真实有效的呢?这就要用到第 25 讲里的知识了,开始走证书链逐级验证,确认证书的真实性,再用证书公钥验证签名,就确认了服务器的身份:“刚才跟我打招呼的不是骗子,可以接着往下走。”

第三阶段:主密钥生成

  1. 客户端通过 RSA 公钥对生成的 pre-master 进行加密,并发送给服务端。
  2. 现在客户端和服务器手里有了三个随机数:Client Random、Server Random 和 Pre-Master。用这三个作为原始材料,就可以生成用于加密会话的主密钥,叫“Master Secret”。
  3. 有了主密钥和派生的会话密钥,客户端发一个“Change Cipher Spec”,然后再发一个“Finished”消息,把之前所有发送的数据做个摘要,再加密一下,让服务器做个验证。
  4. 服务器也发送“Change Cipher Spec”和“Finished”消息,双方都验证加密解密 OK,握手正式结束,后面就收发被加密的 HTTP 请求和响应

ECDHE 握手过程

ECDHE加密算法 第一阶段:明文共享阶段(C/S 两端共享随机数 和 服务器的椭圆曲线加密参数)

  1. 在 TCP 建立连接之后,浏览器会首先发一个“Client Hello”消息,里面有客户端的版本号、支持的密码套件,还有一个随机数(Client Random),用于后续生成会话密钥。
  2. 服务器收到“Client Hello”后,会返回一个“Server Hello”消息。把版本号对一下,也给出一个随机数(Server Random),然后从客户端的列表里选一个作为本次通信使用的密码套件。
  3. 接下来是一个关键的操作,因为服务器选择了 ECDHE 算法,所以它会在证书后发送“Server Key Exchange”消息,里面是椭圆曲线的公钥(Server Params),用来实现密钥交换算法,再加上自己的私钥签名认证。
  4. 服务器为了证明自己的身份,就把证书也发给了客户端(Server Certificate)。
  5. Server Done

这样第一个消息往返就结束了(两个 TCP 包),结果是客户端和服务器通过明文共享了三个信息:Client Random、Server Random 和 Server Params。

第二阶段:证书验证同上

第三阶段:主密钥生成

  1. 客户端按照密码套件的要求,也生成一个椭圆曲线的公钥(Client Params),用“Client Key Exchange”消息发给服务器。
  2. 根据密钥交换算法的两个参数(Client Params、Server Params)用 ECDHE 算法计算出“Pre-Master”,其实也是一个随机数。
  3. 现在客户端和服务器手里有了三个随机数:Client Random、Server Random 和 Pre-Master。用这三个作为原始材料,就可以生成用于加密会话的主密钥,叫“Master Secret”。而黑客因为拿不到“Pre-Master”,所以也就得不到主密钥。
  4. 有了主密钥和派生的会话密钥,客户端发一个“Change Cipher Spec”,然后再发一个“Finished”消息,把之前所有发送的数据做个摘要,再加密一下,让服务器做个验证。
  5. 服务器也发送“Change Cipher Spec”和“Finished”消息,双方都验证加密解密 OK,握手正式结束,后面就收发被加密的 HTTP 请求和响应

和 RSA 加密算法的区别:

  1. 服务器端在发送 Server Hello 时会发出“Server Key Exchange”消息并携带加密算法参数。
  2. 因为使用了 ECDHE,客户端可以不用等到服务器发回“Finished”确认握手完毕,就可以立即发出 HTTP 报文,省去了一个消息往返的时间浪费。这个叫“抢跑”,和“TCP Fast Open”有点像,都是不等连接完全建立就提前发应用数据,提高传输的效率。

TLS1.3 握手

HTTPS 建立连接时除了要做 TCP 握手,还要做 TLS 握手,在 1.2 中会花费两个消息往返(2-RTT),可能导致几十毫秒甚至上百毫秒的延迟,在移动网络中延迟还会更严重。

现在 TLS1.3 密码套件大幅度简化,也就没有必要再像以前那样走复杂的协商流程了,规定必须使用椭圆曲线算法。TLS1.3 压缩了以前的“Hello”协商过程,删除了“Key Exchange”消息,把握手时间减少到了“1-RTT”,效率提高了一倍。

TLS1.3握手
TLS1.3握手

5. HTTPS 优化策略有了解吗?

  • 握手阶段慢
  • 硬件优化
  • 软件优化
  • 协议优化
  • 会话复用: session ID

慢在哪里?

通常所说的“HTTPS 连接慢”指的就是刚开始建立连接的那段时间。在 TCP 建连之后,正式数据传输之前,HTTPS 比 HTTP 增加了一个 TLS 握手的步骤,这个步骤最长可以花费两个消息往返,也就是 2-RTT。而且在握手消息的网络耗时之外,还会有其他的一些“隐形”消耗,比如:产生用于密钥交换的临时公私钥对(ECDHE);验证证书时访问 CA 获取 CRL 或者 OCSP;非对称加密解密处理“Pre-Master”。

硬件优化

HTTPS 连接是计算密集型,而不是 I/O 密集型。

  • 可以选择更快的 CPU,最好还内建 AES 优化,这样即可以加速握手,也可以加速传输。
  • 可以选择“SSL 加速卡”,加解密时调用它的 API,让专门的硬件来做非对称加解密,分担 CPU 的计算压力。
  • 第三种硬件加速方式:“SSL 加速服务器”,用专门的服务器集群来彻底“卸载”TLS 握手时的加密解密计算,性能自然要比单纯的“加速卡”要强大的多。

软件优化

软件升级实施起来比较简单,就是把现在正在使用的软件尽量升级到最新版本,比如把 Linux 内核由 2.x 升级到 4.x,把 Nginx 由 1.6 升级到 1.16,把 OpenSSL 由 1.0.1 升级到 1.1.0/1.1.1。由于这些软件在更新版本的时候都会做性能优化、修复错误,只要运维能够主动配合,这种软件优化是最容易做的,也是最容易达成优化效果的。

协议优化

如果有可能,应当尽量采用 TLS1.3,它大幅度简化了握手的过程,完全握手只要 1-RTT,而且更加安全。

如果暂时不能升级到 1.3,只能用 1.2,那么握手时使用的密钥交换协议应当尽量选用椭圆曲线的 ECDHE 算法。它不仅运算速度快,安全性高,还支持“False Start”,能够把握手的消息往返由 2-RTT 减少到 1-RTT,达到与 TLS1.3 类似的效果。

会话复用

HTTPS 建立连接的过程:先是 TCP 三次握手,然后是 TLS 一次握手。这后一次握手的重点是算出主密钥“Master Secret”,而主密钥每次连接都要重新计算,未免有点太浪费了,如果能够把“辛辛苦苦”算出来的主密钥缓存一下“重用”,不就可以免去了握手和计算的成本了吗?

这种做法就叫“会话复用”(TLS session resumption),和 HTTP Cache 一样,也是提高 HTTPS 性能的“大杀器”,被浏览器和服务器广泛应用。

会话复用分两种,第一种叫“Session ID”,就是客户端和服务器首次连接后各自保存一个会话的 ID 号,内存里存储主密钥和其他相关的信息。当客户端再次连接时发一个 ID 过来,服务器就在内存里找,找到就直接用主密钥恢复会话状态,跳过证书验证和密钥交换,只用一个消息往返就可以建立安全通信。

会话复用握手
会话复用握手