前端关于网络安全问题看似高深莫测,其实来来回回就那么点东西,我总结一下就是 3 + 1 ?= 4,3个用字母描述的【分别是 XSS、CSRF、CORS】 + 一个中间人攻击。当然 CORS 同源策略是为了防止攻击的安全策略,其他的都是网络攻击。除了这 4 个前端相关的面试题,其他的都是一些不常用的小喽啰。
我将会在我的《面试题一网打尽》专栏中先逐一详细介绍,然后再来一篇文章总结,预计一共5篇文章,欢迎大家关注~
本篇文章是前端网络安全相关的第四篇文章,内容就是关于中间人攻击,欢迎收藏加关注。
本篇文章的基础是需要一个服务端的项目,可以跟着我的这篇文章搭建自己的服务端项目。或者直接克隆我的仓库代码在这个提交上拉一个新分支,本篇文章所有的代码都是在这个提交基础上进行的。
在本篇文章之前,我已经写了 xss 攻击、?csrf 攻击、cors跨域的文章,所以在你拉取我的 git 最新代码的时候,已经有很多更新的提交了。不过,无论是从上面我说的那个提交拉取新分支,还是拉取最新的代码都可以,我的仓库的所有的合并都是相互独立的。
不论你先其他的教程,还是先看这篇中间人攻击的文章都可以。
中间人攻击MITM(Man-in-the-middle Attack)多发生在未加密的通信中,比如 http 就是未加密的明文传输,中间人攻击是一种攻击方式,攻击者插入自己作为通信方之间的“中间人”,以截取、篡改或窃取传输的数据。中间人截取的是传输过程中的数据,任何他觉得有用的数据都可以截取。中间人攻击并不仅仅发生在 HTTP 请求中,它可以发生在任何通过网络传输的通信中,包括 HTTP、SMTP、FTP等。
中间人攻击并不仅限于非加密通信,在加密通信中也会存在比如 https 只不过难度更大。
在一些教程中,介绍的关于中间人攻击的流程中,很多描述的是通信双方有加密的场景,让初学者误以为,只有有加密的场景才是中间人攻击,其实不然。因为 https 加密通信的中间人攻击比较复杂,非加密通信的中间人攻击简单,所以很少有人单独拿出来说。
但是我的这篇文章会详细介绍 【http 非加密通信的中间人攻击】和 【https 加密通信的中间人攻击】
在 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 这种非加密通信中的 中间人攻击。
强调一下,如果你对下面这些构建服务的内容有疑问或者不懂的,我建议你先看一下我的这篇关于构建 express 服务的文章。
在 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>
在 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);
npm run dev middleman
我们需要一个抓包工具模拟中间人攻击,无论你用那种抓包工具都可以,有很多可以选择的,找一个你觉得好用的就行。
我这里使用的是 whistle, 感觉还挺好用的。
whistle 貌似不能拦截 localhost 地址的请求,不知道其他的工具能不能,不过不重要,我们在模拟的时候可以使用 ip 地址。
这就是一个简单的中间人攻击,中间人就是我们的抓包工具,拦截了请求,伪造了返回结果,这样就会给用户造成困扰。
注意,我们本地的服务是一个 http 的服务,你要知道 http 是明文传输,非加密的请求,所以我们可以随意的抓包,进行中间人攻击。
这种中间人攻击比较简单,所以很多面试题详解的中间人攻击过程,其实都不是这种简单的抓包,更多的是 https 的中间人攻击,包括公钥、私钥啥的,继续看,我们后面会讲到。
为了防范中间人攻击才推出了 https 加密传输协议。
http | https | |
明文传输 | 密文传输 | |
默认端口 | 80 | 443 |
是否安全 | 不安全 | 安全 |
是否加密 | 否 | 使用 TLS / SSL加密 |
https 是基于 http 的安全版本,实际上是在 http 之上添加了安全性和加密协议,它使用TLS(Transport Layer Security)或其前身SSL(Secure Sockets Layer)来加密在客户端和服务器之间传输的数据。
关于 https 的加密逻辑又是一大堆知识点,可以后续写一篇文章,现在可以大概说一下:
https? 使用非对称加密加密密钥,使用对称加密加密数据。?
https 基于 PKI 技术。PKI(Public Key Infrastructure,公钥基础设施)是一种安全体系结构,用于管理数字证书和密钥对,以确保安全的数据传输和身份验证。PKI 采用了公钥加密技术,其中每个实体都有一个公钥和一个私钥,这对密钥用于加密和解密通信。
使用一个哈希函数对文档进行摘要运算,生成一个固定长度的哈希值,这个哈希值通常称为信息摘要。
在前端领域,关于哈希函数这个概念还有哪些地方会用到?
(1)路由导航的 #号 表示的哈希路由
(2)资源打包之后会给文件名加上哈希值,用于静态资源完整性校验
(3)前端缓存管理,也可以使用哈希函数对数据进行缓存,防止健名冲突?
常用的信息摘要算法:
(1)信息摘要的目的,主要是为了防止数据被篡改,所以哈希算法是不可逆的
(2)信息摘要是唯一的,同一个数据用同样的哈希函数,得到的值是一定的。
对称加密 | 非对称加密 |
一个密钥 | 两个密钥【公钥、私钥】 |
速度快 | 速度慢 |
DES、AES | RSA、ECC |
在加密通信中,公钥和私钥是一对密钥,通常用于非对称加密算法。这些算法允许一个密钥用于加密,而另一个密钥用于解密,其中:
公钥(Public Key): 公钥是一种可以自由分发的密钥,用于加密数据。任何人都可以使用公钥对数据进行加密,但只有拥有与之配对的私钥的实体才能解密这些数据。公钥通常用于加密通信中的敏感信息,例如用于建立安全连接或传输敏感数据。
私钥(Private Key): 私钥是一种保密的密钥,只有密钥的所有者知道。私钥用于解密由相应的公钥加密的数据。私钥通常用于解密接收到的加密数据,以及对数字签名进行生成或验证。私钥必须始终保持保密,以确保通信的机密性和完整性。
那么问题来了,如何生成公钥和私钥?
有公钥和私钥一定是非对称加密,通常使用?OpenSSL 生成公钥和私钥。【这看起来也不是前端的工作,哈哈】
数字签名是一种用于验证电子文档真实性和完整性的技术。通过数字签名,发送者可以在文档上附加一个数字签名,接收者可以使用签名验证工具来确认文档的来源和是否在传输过程中被篡改。
数字签名防止数据被篡改这一点和信息摘要算法的作用是一样的。但是数字签名有更多的信息,相当于是信息摘要的一个扩展应用。
选择哈希算法: 首先,选择一个哈希算法,例如SHA-256。哈希算法用于将消息或文档转换为固定长度的哈希值。【生成签名一定要有哈希算法】
创建消息摘要: 使用选择的哈希算法对消息或文档进行哈希,得到一个称为消息摘要(message digest)的固定长度字符串。这个摘要是消息内容的唯一表示。
使用私钥进行加密: 数字签名的生成涉及使用私钥对消息摘要进行加密。这个过程使用的是非对称加密算法,通常是使用数字签名算法中的私钥。
将签名附加到原始消息或文档: 将生成的数字签名附加到原始消息或文档中,形成带有数字签名的消息。
消息摘要(Message Digest): 发送者使用一个哈希函数对要签名的文档进行摘要运算,生成一个固定长度的哈希值。这个哈希值通常称为消息摘要。【消息摘要就是信息摘要】
私钥签名: 发送者使用自己的私钥对消息摘要进行加密,形成数字签名。
公钥验证: 接收者使用发送者的公钥对数字签名进行解密,得到消息摘要。
验证摘要: 接收者再次对接收到的文档进行哈希运算,得到一个新的消息摘要。
比较摘要: 接收者将用公钥解密得到的消息摘要与重新计算得到的摘要进行比较。如果两者一致,说明文档未被篡改且确实来自于私钥持有者。
数字证书是一种用于在网络通信中验证身份和确保数据传输安全的安全工具。它是由数字签名和公钥加密技术结合而成的一种电子凭证。数字证书通常包含以下信息:
主体信息(Subject): 证书中标识了证书的所有者,通常是一个实体(个人、组织或设备)的名称。
公钥: 证书中包含了与证书所有者相关联的公钥,用于加密和解密通信中的数据。
数字签名: 数字证书通过使用颁发者(Certificate Authority,CA)的私钥对证书中的数据进行签名,以确保证书的完整性和真实性。
颁发者信息(Issuer): 证书中标识了颁发该证书的CA的信息。
有效期: 证书包含了一个指定的有效期范围,确保证书在一段时间后会过期,从而促使证书的定期更新。
生成密钥对: 实体首先生成一对非对称密钥,包括公钥和私钥。通常使用算法如RSA或ECC进行密钥对的生成。
创建证书请求(CSR): 实体生成一个包含其公钥以及其他相关信息的证书请求。这个请求包括实体的标识信息,例如域名、组织名称等。
提交证书请求: 将证书请求发送给证书颁发机构(CA)。CA是一个受信任的第三方机构,负责验证请求者的身份并颁发数字证书。
验证身份: CA对证书请求进行身份验证,以确保请求者拥有提供的标识信息(域名、组织等)。这可能包括域名验证、组织验证等。
颁发数字证书: CA验证成功后,颁发数字证书。数字证书包含实体的公钥,以及与证书相关的元数据,如证书有效期、签名算法等。
证书签名: CA 使用自己的私钥对数字证书中的信息进行签名,生成数字签名。这个签名可以被验证以确保证书的完整性和真实性。
证书发布: CA将数字证书返回给实体,实体将其安装在其服务器或应用程序中。
使用数字证书: 数字证书现在可以用于建立安全的通信通道,例如在HTTPS中,客户端和服务器可以相互验证身份并使用证书中的公钥进行加密通信。
啰里八嗦一大堆,我们总结一下我们只要理解数字证书咋来的就能理解这些概念,大概步骤如下:
理论上 https 是设计用于防范中间人攻击的,因为它是用加密机制来保护数据在客户端和服务器之间的传输,https 通过 TLS(Transport Layer Security)和SSL(Secure Sockets Layer) 协议加密通信,使得中间人在截获数据时无法解密敏感信息,但是,虽然 https 提供来重要的安全性增强,仍然在一些可能的中间人攻击场景。
我们可以模拟的场景其实就是第一个,证书劫持,我们在之后使用抓包工具如果想要拦截https 的请求,也需要安装一个根证书。
比如我用的抓包工具 whistle 就需要这样设置。
在上面 1 - 11 这个过程中,中间人只做了数据的窃取,中间人还可以进行数据的篡改,比如发给客户端的数据是自己胡编乱造的,总之会对客户端用户造成很大的影响,这就是中间人攻击。
依旧使用我们在 2.4 中的服务,但是我们要模拟 https 攻击需要使用 whistle 进行域名映射把
http://10.10.25.120:3000? 映射到 https://a.com
然后拦截?https://a.com 的请求,并篡改返回。
想要拦截 https 请求,首先需要安装一个根证书,信任这个根证书,然后在 whistle 中选中这两个选项。
修改请求的返回值
至此中间人攻击的全部流程已经解释完毕。
我的仓库地址如下,欢迎查看
内容较多,难免疏漏,如有问题,欢迎指正。
?这是一个系列文章,欢迎关注我的专栏《面试题一网打尽》,持续更新中。