前言
前端关于网络安全问题看似高深莫测,其实来来回回就那么点东西,我总结一下就是 3 + 1 = 4,3个用字母描述的【分别是 XSS、CSRF、CORS】 + 一个中间人攻击。当然 CORS 同源策略是为了防止攻击的安全策略,其他的都是网络攻击。除了这 4 个前端相关的面试题,其他的都是一些不常用的小喽啰。
我将会在我的《面试题一网打尽》专栏中先逐一详细介绍,然后再来一篇文章总结,预计一共5篇文章,欢迎大家关注~
本篇文章是前端网络安全相关的第四篇文章,内容就是关于中间人攻击,欢迎收藏加关注。
一、准备工作
1.1 拉取仓库
本篇文章的基础是需要一个服务端的项目,可以跟着我的这篇文章搭建自己的服务端项目。或者直接克隆我的仓库代码在这个提交上拉一个新分支,本篇文章所有的代码都是在这个提交基础上进行的。
在本篇文章之前,我已经写了 xss 攻击、 csrf 攻击、cors跨域的文章,所以在你拉取我的 git 最新代码的时候,已经有很多更新的提交了。不过,无论是从上面我说的那个提交拉取新分支,还是拉取最新的代码都可以,我的仓库的所有的合并都是相互独立的。
不论你先其他的教程,还是先看这篇中间人攻击的文章都可以。
1.2 新增 middleman 文件夹
二、中间人攻击原理
2.1 攻击原理
中间人攻击MITM(Man-in-the-middle Attack)多发生在未加密的通信中,比如 http 就是未加密的明文传输,中间人攻击是一种攻击方式,攻击者插入自己作为通信方之间的“中间人”,以截取、篡改或窃取传输的数据。中间人截取的是传输过程中的数据,任何他觉得有用的数据都可以截取。中间人攻击并不仅仅发生在 HTTP 请求中,它可以发生在任何通过网络传输的通信中,包括 HTTP、SMTP、FTP等。
中间人攻击并不仅限于非加密通信,在加密通信中也会存在比如 https 只不过难度更大。
在一些教程中,介绍的关于中间人攻击的流程中,很多描述的是通信双方有加密的场景,让初学者误以为,只有有加密的场景才是中间人攻击,其实不然。因为 https 加密通信的中间人攻击比较复杂,非加密通信的中间人攻击简单,所以很少有人单独拿出来说。
但是我的这篇文章会详细介绍 【http 非加密通信的中间人攻击】和 【https 加密通信的中间人攻击】
2.2 常见形式
- 拦截和查看: 攻击者截取传输中的数据包,并查看其中的内容,可能包括敏感信息。
- 篡改: 攻击者可能修改传输中的数据包,以执行恶意操作,如注入恶意代码或篡改页面内容。
- 重放攻击: 攻击者可能记录先前的通信并重放其中的某些请求,以试图欺骗服务器或客户端。
- SSL Stripping: 在HTTPS通信中,攻击者可能试图将连接转换为不安全的HTTP连接,从而绕过加密。【中间人和用户建立http 连接,中间人冒充用户与服务器建立https连接】
2.3 防范措施
- 使用 HTTPS: 对于敏感信息的传输,始终使用HTTPS,以确保通信是加密的。
- 使用可靠的证书: 在HTTPS 通信中,使用受信任的 SSL/TLS 证书,以确保通信的安全性。
- 安全的公共 Wi-Fi: 在使用公共 Wi-Fi 时,尽量避免访问敏感信息,因为这些网络可能容易受到中间人攻击。
- 强大的身份验证: 使用强大的身份验证机制,如多因素身份验证,以减少身份被盗用的风险。
- 持续监控和检测: 实施监控和检测机制,以及时发现并应对中间人攻击。
在 HTTPS 通信中,数据包是经过加密的,可以增加中间人攻击的难度,但中间人攻击仍然可能发生,攻击者可以尝试使用各种技术解密或篡改加密通信。中间人攻击是一个缺乏相互认证的攻击,https 中的 ssl 协议可以验证参与通讯的一方或双方使用的证书是否是权威受信任的数字证书认证机构颁发,并且能执行双向身份认证。【信任链】
为什么公共 Wi-Fi 是不安全的?
- 通常公共 Wi-Fi 不启用 Wi-Fi 加密协议,Wi-Fi 加密协议不是 https,【不要一想到加密就想到https 】。Wi-Fi 加密协议有 wep、wpa、wpa2、wpa3 等,这些协议可以加密通过 Wi-Fi 网络传输的数据,防止被不相关的第三方截取,防止中间人攻击。
- 在一个公共 Wi-Fi 中,即使网站使用了 https,Wi-Fi 本身没有启用加密,攻击者仍可以截取 Wi-Fi 数据包,尽管这些数据包中的具体内容是加密的。中间人攻击者仍可以能够分析 Wi-Fi 流量的模式、抓取一些元数据,或者使用其他手段来识别用户的行为。
三、http 中间人攻击
我们接下来模拟 http 这种非加密通信中的 中间人攻击。
3.1 构建本地服务
强调一下,如果你对下面这些构建服务的内容有疑问或者不懂的,我建议你先看一下我的这篇关于构建 express 服务的文章。
3.1.1 新建 index.html
在 middleman 文件夹下面新建 index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>middleman<script>function init() {fetch('info').then((res) => {return res.json()}).then((data) => {console.log('请求成功', data)})}init()</script>
</body>
</html>
3.1.2 新建 index.js
在 middleman 文件夹下面新建 index.js
const express = require('express');
const path = require('path')
const cors = require('cors')
const app = express();
app.use(cors())app.get('/', function (req, res) {res.sendFile(path.join(__dirname, '/index.html'));
});app.get('/info', function(req, res){res.send({text: 'success'})
})
app.listen(3000);
3.1.3 运行服务
npm run dev middleman
3.2 使用 whistle 拦截请求
我们需要一个抓包工具模拟中间人攻击,无论你用那种抓包工具都可以,有很多可以选择的,找一个你觉得好用的就行。
我这里使用的是 whistle, 感觉还挺好用的。
whistle 貌似不能拦截 localhost 地址的请求,不知道其他的工具能不能,不过不重要,我们在模拟的时候可以使用 ip 地址。
3.2.1 运行我们的服务
3.2.2 使用 whistle 拦截请求
3.2.3 伪造请求的返回
3.2.4 刷新本地服务
这就是一个简单的中间人攻击,中间人就是我们的抓包工具,拦截了请求,伪造了返回结果,这样就会给用户造成困扰。
注意,我们本地的服务是一个 http 的服务,你要知道 http 是明文传输,非加密的请求,所以我们可以随意的抓包,进行中间人攻击。
这种中间人攻击比较简单,所以很多面试题详解的中间人攻击过程,其实都不是这种简单的抓包,更多的是 https 的中间人攻击,包括公钥、私钥啥的,继续看,我们后面会讲到。
四、https 基础知识
为了防范中间人攻击才推出了 https 加密传输协议。
4.1 http 和 https 的区别
http | https | |
明文传输 | 密文传输 | |
默认端口 | 80 | 443 |
是否安全 | 不安全 | 安全 |
是否加密 | 否 | 使用 TLS / SSL加密 |
https 是基于 http 的安全版本,实际上是在 http 之上添加了安全性和加密协议,它使用TLS(Transport Layer Security)或其前身SSL(Secure Sockets Layer)来加密在客户端和服务器之间传输的数据。
关于 https 的加密逻辑又是一大堆知识点,可以后续写一篇文章,现在可以大概说一下:
https 使用非对称加密加密密钥,使用对称加密加密数据。
4.2 PKI 公钥基础设施
https 基于 PKI 技术。PKI(Public Key Infrastructure,公钥基础设施)是一种安全体系结构,用于管理数字证书和密钥对,以确保安全的数据传输和身份验证。PKI 采用了公钥加密技术,其中每个实体都有一个公钥和一个私钥,这对密钥用于加密和解密通信。
4.2.1 信息摘要
使用一个哈希函数对文档进行摘要运算,生成一个固定长度的哈希值,这个哈希值通常称为信息摘要。
在前端领域,关于哈希函数这个概念还有哪些地方会用到?
(1)路由导航的 #号 表示的哈希路由
(2)资源打包之后会给文件名加上哈希值,用于静态资源完整性校验
(3)前端缓存管理,也可以使用哈希函数对数据进行缓存,防止健名冲突
常用的信息摘要算法:
- md5 生成128位的哈希值,但由于其容易被碰撞攻击破解,已经不再被广泛使用于安全领域,但是在业务逻辑中常用,把一个文件进行摘要获得唯一的哈希值,可以用来判断文件是否被修改。【前端经常用到的 md5 的npm 包】
- SHA-256、SHA-384、SHA-512: 属于SHA-2系列,分别生成256位、384位和512位的哈希值。目前在许多安全应用中仍然广泛使用。【前端经常使用crypto-js】
(1)信息摘要的目的,主要是为了防止数据被篡改,所以哈希算法是不可逆的
(2)信息摘要是唯一的,同一个数据用同样的哈希函数,得到的值是一定的。
4.2.2 对称加密和非对称加密
对称加密 | 非对称加密 |
一个密钥 | 两个密钥【公钥、私钥】 |
速度快 | 速度慢 |
DES、AES | RSA、ECC |
4.2.3 公钥和私钥
在加密通信中,公钥和私钥是一对密钥,通常用于非对称加密算法。这些算法允许一个密钥用于加密,而另一个密钥用于解密,其中:
-
公钥(Public Key): 公钥是一种可以自由分发的密钥,用于加密数据。任何人都可以使用公钥对数据进行加密,但只有拥有与之配对的私钥的实体才能解密这些数据。公钥通常用于加密通信中的敏感信息,例如用于建立安全连接或传输敏感数据。
-
私钥(Private Key): 私钥是一种保密的密钥,只有密钥的所有者知道。私钥用于解密由相应的公钥加密的数据。私钥通常用于解密接收到的加密数据,以及对数字签名进行生成或验证。私钥必须始终保持保密,以确保通信的机密性和完整性。
那么问题来了,如何生成公钥和私钥?
有公钥和私钥一定是非对称加密,通常使用 OpenSSL 生成公钥和私钥。【这看起来也不是前端的工作,哈哈】
4.2.4 数字签名
数字签名是一种用于验证电子文档真实性和完整性的技术。通过数字签名,发送者可以在文档上附加一个数字签名,接收者可以使用签名验证工具来确认文档的来源和是否在传输过程中被篡改。
数字签名防止数据被篡改这一点和信息摘要算法的作用是一样的。但是数字签名有更多的信息,相当于是信息摘要的一个扩展应用。
(1)数字签名生成的过程:
-
选择哈希算法: 首先,选择一个哈希算法,例如SHA-256。哈希算法用于将消息或文档转换为固定长度的哈希值。【生成签名一定要有哈希算法】
-
创建消息摘要: 使用选择的哈希算法对消息或文档进行哈希,得到一个称为消息摘要(message digest)的固定长度字符串。这个摘要是消息内容的唯一表示。
-
使用私钥进行加密: 数字签名的生成涉及使用私钥对消息摘要进行加密。这个过程使用的是非对称加密算法,通常是使用数字签名算法中的私钥。
-
将签名附加到原始消息或文档: 将生成的数字签名附加到原始消息或文档中,形成带有数字签名的消息。
(2)数字签名的基本原理包括:
-
消息摘要(Message Digest): 发送者使用一个哈希函数对要签名的文档进行摘要运算,生成一个固定长度的哈希值。这个哈希值通常称为消息摘要。【消息摘要就是信息摘要】
-
私钥签名: 发送者使用自己的私钥对消息摘要进行加密,形成数字签名。
-
公钥验证: 接收者使用发送者的公钥对数字签名进行解密,得到消息摘要。
-
验证摘要: 接收者再次对接收到的文档进行哈希运算,得到一个新的消息摘要。
-
比较摘要: 接收者将用公钥解密得到的消息摘要与重新计算得到的摘要进行比较。如果两者一致,说明文档未被篡改且确实来自于私钥持有者。
4.2.5 数字证书
数字证书是一种用于在网络通信中验证身份和确保数据传输安全的安全工具。它是由数字签名和公钥加密技术结合而成的一种电子凭证。数字证书通常包含以下信息:
-
主体信息(Subject): 证书中标识了证书的所有者,通常是一个实体(个人、组织或设备)的名称。
-
公钥: 证书中包含了与证书所有者相关联的公钥,用于加密和解密通信中的数据。
-
数字签名: 数字证书通过使用颁发者(Certificate Authority,CA)的私钥对证书中的数据进行签名,以确保证书的完整性和真实性。
-
颁发者信息(Issuer): 证书中标识了颁发该证书的CA的信息。
-
有效期: 证书包含了一个指定的有效期范围,确保证书在一段时间后会过期,从而促使证书的定期更新。
数字证书形成步骤:
-
生成密钥对: 实体首先生成一对非对称密钥,包括公钥和私钥。通常使用算法如RSA或ECC进行密钥对的生成。
-
创建证书请求(CSR): 实体生成一个包含其公钥以及其他相关信息的证书请求。这个请求包括实体的标识信息,例如域名、组织名称等。
-
提交证书请求: 将证书请求发送给证书颁发机构(CA)。CA是一个受信任的第三方机构,负责验证请求者的身份并颁发数字证书。
-
验证身份: CA对证书请求进行身份验证,以确保请求者拥有提供的标识信息(域名、组织等)。这可能包括域名验证、组织验证等。
-
颁发数字证书: CA验证成功后,颁发数字证书。数字证书包含实体的公钥,以及与证书相关的元数据,如证书有效期、签名算法等。
-
证书签名: CA 使用自己的私钥对数字证书中的信息进行签名,生成数字签名。这个签名可以被验证以确保证书的完整性和真实性。
-
证书发布: CA将数字证书返回给实体,实体将其安装在其服务器或应用程序中。
-
使用数字证书: 数字证书现在可以用于建立安全的通信通道,例如在HTTPS中,客户端和服务器可以相互验证身份并使用证书中的公钥进行加密通信。
4.2.6 PKI 关键组件的功能
- 证书颁发机构(Certificate Authority): CA 是 PKI 的核心组成部分,负责验证个体或实体的身份,并颁发数字证书。CA 签署证书,用于证明数字证书的真实性。中国的 CA 机构有。【注意这是一个机构,或者说一个公司】
- 中国互联网络信息中心(CNNIC)
- CFCA(中国金融认证中心)
- WoSign(沃通根证书认证机构)
- 数字证书: 数字证书是包含公钥及相关身份信息的文件,由CA签发。数字证书用于在网络上建立信任,确保通信方的身份。
- 注册机构(Registration Authority): RA 是 CA 的协助机构,负责验证证书请求者的身份信息,并将验证结果提交给 CA。RA在某些情况下可以由 CA 直接处理。
- 证书存储库: 证书存储库用于存储和检索数字证书。它是一个安全的存储区域,通常由 CA进行管理。
- 密钥对生成和管理: PKI 系统支持生成和管理加密算法所需的密钥对,包括公钥和私钥。这确保了通信的安全性,同时也涉及密钥的定期轮换和更新。
- 证书撤销列表(CRL): CRL 是CA 发布的一个列表,包含被吊销的数字证书的信息。这允许验证方检查证书是否仍然有效。
- 数字签名: PKI 使用数字签名来保证证书的真实性和完整性。数字签名是用私钥生成的,可通过公钥验证。
4.3 小结
啰里八嗦一大堆,我们总结一下我们只要理解数字证书咋来的就能理解这些概念,大概步骤如下:
- 哈希算法 + 消息 = 信息摘要
- 信息摘要 + 私钥 = 数字签名
- 数字签名 + 实体信息 = 数字证书
五、https 中间人攻击
理论上 https 是设计用于防范中间人攻击的,因为它是用加密机制来保护数据在客户端和服务器之间的传输,https 通过 TLS(Transport Layer Security)和SSL(Secure Sockets Layer) 协议加密通信,使得中间人在截获数据时无法解密敏感信息,但是,虽然 https 提供来重要的安全性增强,仍然在一些可能的中间人攻击场景。
5.1 攻击场景
- 证书劫持: 从证书颁发机构(CA)处获取伪造证书或通过其他方式获取目标网站的合法证书
- 恶意证书颁发机构: 恶意的证书颁发机构,从而允许攻击者创建伪造的SSL证书。
- SSL剥离(SSL Stripping): 攻击者可能尝试将HTTPS连接转换为不安全的HTTP连接,使得攻击者能够查看和修改未加密的通信,降级攻击
- SSL/TLS漏洞: SSL/TLS 协议本身存在漏洞
- 弱密码或弱密钥: 如果 SSL/TLS 使用弱密码或弱密钥,可能使攻击者很容易破解加密
我们可以模拟的场景其实就是第一个,证书劫持,我们在之后使用抓包工具如果想要拦截https 的请求,也需要安装一个根证书。
比如我用的抓包工具 whistle 就需要这样设置。
5.2 防范攻击
- 使用受信任的证书颁发机构(CA)颁发SSL证书。
- 实施公共密钥基础设施(PKI)以确保证书的真实性。
- 启用HTTP Strict Transport Security(HSTS)以防止协议降级攻击。【SSL剥离】
- 定期检查和更新服务器和 SSL/TLS 库以修复已知漏洞。
- 在 Web 应用程序中实施安全性最佳实践,如使用安全的 Cookie 标记、避免混合内容、配置CSP(内容安全策略)等。
5.3 攻击流程
- 客户端发送 https 请求
- 中间人截获 https 请求,然后在转发给服务端
- 中间人可以是抓包工具
- 中间人可以通过伪造证书的方式截获请求
- 服务端接收到请求【看起来是客户端发的,实际上已经经过中间人转发了】
- 服务端以为是一个安全的请求,向客户端发送数字证书,假设为 DC_A,证书中包含公钥和CA等信息。
- 作为 https 请求的服务端一定是购买了安全的证书,否则会提示不是安全的链接
- 数字证书里面包含是公钥 PK_A,服务端私密保存数字证书对应的私钥SK_A
- 作为 https 请求的服务端一定是购买了安全的证书,否则会提示不是安全的链接
- 中间人截获数字证书 DC_A,使用 OpenSSL 提取其中的公钥 PK_A。然后把自己的数字证书 DC_B 发送给客户端
- 中间人有自己的数字证书,其中数字证书包含了自己的公钥 PK_B ,中间人私密保存自己的私钥 SK_B。
- 客户端接收到数字证书 DC_B【这个证书看起来是服务端发的,实际上是中间人的】,客户端会验证数字证书是否有效,步骤如下:
- 证书链验证:客户端检查证书是否由受信任的根证书颁发机构(CA)签发,通过信任链验证证书的有效性。
- 客户端的操作系统中内置了根证书,根证书通常用于验证 CA 。
- 根证书验证 CA 的流程是(信任链):信任设备的根证书 (操作系统内置)=> 信任根证书签发它的 CA => CA 信任颁发它的中间 CA => 以此类推,最终信任根证书签发的所有数字证书
- 所以,验证数字证书的本质是验证 CA
- 所以我们在实现中间人攻击之前,需要在我们的电脑上安装一个新的根证书,这个根证书就是用来验证中间人的数字证书的。【这个根证书和中间人证书是一个CA 签发的】
- 有效期验证:检查证书是否在有效期内
- 吊销状态检查:检查证书是否被吊销
- 证书链验证:客户端检查证书是否由受信任的根证书颁发机构(CA)签发,通过信任链验证证书的有效性。
- 客户端验证证书 DC_B 有效后,提取公钥 PK_B,并用公钥 PK_B 加密一个数据当作后续对称加密的私钥,这个数据通常是随机字符串使用哈希算法得到的哈希值,这里假设是 hash_B。
- 中间人拦截请求,得到使用自己的公钥 PK_B 加密的哈希值 hash_B,用自己的私钥 SK_B 解密,得到真实的哈希值 hash_B,这个真实的哈希值后续用来解密所有拦截的客户端的请求。
- 中间人再生成一个假的随机字符串 hash_A,用服务端的公钥 PK_A 加密,发给服务端。
- 服务端接收到请求,用自己的私钥 SK_A 解密得到哈希值 hash_A,他以为是客户端发的,实际是中间人伪造的;后续客户端用这个哈希值 hash_A 加密数据,和客户端进行后续的对称加密会话。
- 中间人拦截服务端的返回,用第8步假的哈希值 hash_A 就可以解密(因为是对称加密),然后再用 hash_B 加密,发给客户端
- 客户端接收到中间人用 hash_B 加密的数据,再用 hash_B 解密,就得到了服务端发送的数据。
在上面 1 - 11 这个过程中,中间人只做了数据的窃取,中间人还可以进行数据的篡改,比如发给客户端的数据是自己胡编乱造的,总之会对客户端用户造成很大的影响,这就是中间人攻击。
5.4 代码模拟
依旧使用我们在 2.4 中的服务,但是我们要模拟 https 攻击需要使用 whistle 进行域名映射把
http://10.10.25.120:3000 映射到 https://a.com
然后拦截 https://a.com 的请求,并篡改返回。
5.4.1 本地服务映射为 https
5.4.2 拦截 https 请求
想要拦截 https 请求,首先需要安装一个根证书,信任这个根证书,然后在 whistle 中选中这两个选项。
修改请求的返回值
总结
至此中间人攻击的全部流程已经解释完毕。
我的仓库地址如下,欢迎查看
yangjihong2113/learn-express
内容较多,难免疏漏,如有问题,欢迎指正。
这是一个系列文章,欢迎关注我的专栏《面试题一网打尽》,持续更新中。