CSRF跨站请求伪造攻击原理与防御

CSRF跨站请求伪造攻击原理与防御

概述

跨站请求伪造(Cross-Site Request Forgery,简称 CSRF)是一种常见且危害严重的网络安全攻击技术。攻击者通过伪造用户的请求,利用受害者在目标网站的登录态,诱导用户在不知情的情况下执行非法操作。CSRF攻击广泛存在于WEB应用中,尤其对具有权限操作(如用户信息修改、资金转账、发帖等)的接口威胁巨大。

本文将系统剖析CSRF攻击的原理,结合实战环境还原攻击场景,详解多种防御机制,并辅以代码示例,帮助具备一定基础的技术人员深化理解与实践防御能力。


原理分析

CSRF攻击的核心概念

CSRF攻击基于“用户浏览器自动携带身份凭证”的特性。当客户端登录某网站后,通常会保持登录态(Cookies、Session等),此时所有对该网站的请求都会自动携带有效身份信息。攻击者在另一个恶意网站中植入伪造请求,将这请求发送给目标网站。如果目标网站未做有效防护,将误以为是合法用户发起的操作,从而执行攻击者所设计的非法动作。

攻击流程

  1. 受害者登录受信任网站(目标网站),浏览器获得并保留登录凭据(如Cookie)。
  2. 受害者访问攻击者控制的恶意网站。
  3. 恶意网站构造一个HTTP请求指向目标网站敏感接口,如修改密码、转账等。
  4. 浏览器自动带上目标网站的Cookie等凭证,发送请求。
  5. 目标网站接收到请求,并验证凭证后执行操作,从而实现攻击。

CSRF攻击条件总结

  • 有状态会话机制:目标网站依赖Cookie或其他认证凭证识别用户。
  • 自动携带凭证:浏览器遵照同源策略之外,请求自动带上Cookie。
  • 缺少请求验证机制:服务器端未能准确判断请求是否由用户真实操作发起。

CSRF 与 XSS 的区别

  • CSRF利用的是受害者的身份权限,通过跨站请求执行操作。
  • **XSS(跨站脚本攻击)**则是攻击者在目标网站注入恶意脚本,直接控制用户浏览器执行恶意代码。

实战步骤

环境准备

假设存在一个简单的电商网站,其用户登录后能够修改收货地址(POST请求 /user/update_address)。该接口未做CSRF防护。

实际攻击示例

1. 伪造请求结构

恶意站点插入如下HTML:

<form action="https://targetsite.com/user/update_address" method="POST" id="csrfForm">
  <input type="hidden" name="address" value="攻击者地址信息" />
</form>
<script>
  document.getElementById('csrfForm').submit();
</script>

2. 攻击原理演示

  • 受害者登录 targetsite.com ,获得登录态Cookie。
  • 访问攻击站点,自动触发伪造请求。
  • 浏览器带上目标站点Cookie,服务端误以为是合法操作,修改用户地址。

3. 验证漏洞

查看用户地址是否被非法更改,即为CSRF攻击成功。


代码示例:Token防御机制

最常用且有效的防御措施是使用同步请求防御令牌CSRF Token

服务器端生成Token(示例基于Node.js/Express)

const express = require('express');
const crypto = require('crypto');
const cookieParser = require('cookie-parser');
const app = express();

app.use(cookieParser());
app.use(express.urlencoded({ extended: true }));

// 中间件生成CSRF Token
app.use((req, res, next) => {
  if (!req.cookies.csrfToken) {
    const token = crypto.randomBytes(24).toString('hex');
    res.cookie('csrfToken', token, { httpOnly: true, sameSite: 'strict' });
    req.csrfToken = token;
  } else {
    req.csrfToken = req.cookies.csrfToken;
  }
  next();
});

// 渲染带Token的页面
app.get('/user/profile', (req, res) => {
  const formHtml = `
    <form action="/user/update_address" method="POST">
      <input name="address" type="text" />
      <input type="hidden" name="csrfToken" value="${req.csrfToken}" />
      <button type="submit">更新地址</button>
    </form>
  `;
  res.send(formHtml);
});

// 接收请求时验证Token
app.post('/user/update_address', (req, res) => {
  const userToken = req.body.csrfToken;
  const cookieToken = req.cookies.csrfToken;

  if (!userToken || userToken !== cookieToken) {
    return res.status(403).send('CSRF Token 不匹配,禁止操作');
  }
  
  // 处理地址更新逻辑
  res.send('地址更新成功');
});

app.listen(3000);

说明

  • 服务端生成Token存于HTTP Only Cookie中,只读不暴露给JS,防止XSS窃取。
  • 前端通过隐藏表单域提交Token,服务端比对请求参数和Cookie中Token是否一致。
  • 不一致即阻断,能有效防止伪造请求提交。

防御建议

1. CSRF Token

  • 每个用户会话生成唯一且难以预测的Token。
  • Token需与请求一起提交(隐藏域、请求头)。
  • 服务器严格验证。
  • 结合SameSite Cookie 属性增强防护。

2. 使用 SameSite Cookie 属性

  • SameSite=Lax:禁止跨站提交影 响登录数据提交。
  • SameSite=Strict:更严格,同站请求才发送 Cookie,但提升用户体验时需谨慎使用。

3. 双重提交Cookie(Double Submit Cookie)

  • 服务器发放Token存于Cookie,客户端从Cookie读取Token放入请求中。
  • 服务器检验两者是否一致,缺点是Token存于Cookie中,易被XSS攻击。

4. 验证HTTP请求特征

  • 检验Referer头 and Origin头部,仅接受来自同源的请求。
  • 但部分用户隐私工具会隐藏Referer,误判风险较大。

5. 采用非幂等请求协议

  • 对关键操作,推荐使用POST且附加验证码、二次确认等防护措施。
  • 避免将敏感操作暴露为GET请求。

6. 前端框架防护

  • 现代前端框架(如React、Vue等)和HTTP库(Axios、Fetch)通常支持自动附加CSRF Token。
  • 结合后端验证,形成闭环。

总结

CSRF是一种依赖用户会话机制和浏览器自动携带凭证的跨站攻击,易于被忽视但危害巨大。防护的关键在于对请求有效性进行验证,常用且实践成熟的方案是同步令牌机制(CSRF Token),结合HTTP头校验与安全Cookie策略。作为安全专家,务必在设计应用接口时,从架构和实现层面系统性部署CSRF防护,绝不可将安全留白。

随着Web生态演进,CDN、浏览器策略和框架更新也会影响CSRF防御策略的选型和配置,应持续关注行业动态和最佳实践,不断增强应用安全硬度。


参考阅读(可自选):

  • OWASP官方CSRF防御指南
  • 同源策略与Cookie安全架构详解
  • Web应用安全最佳实践白皮书