全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-16 8 分钟 ✍️ juanwangdev

跨站请求伪造(CSRF)防御

CSRF攻击利用用户已认证身份,诱导用户发起恶意请求,是Web安全的重要防线。

攻击原理

CSRF(Cross-Site Request Forgery)攻击流程:

  1. 用户登录受信任网站A,获取认证Cookie
  2. 用户访问恶意网站B
  3. 网站B向网站A发送伪造请求
  4. 浏览器自动携带网站A的Cookie
  5. 网站A误认为是用户本人操作

典型攻击场景

HTML
<!-- 恶意网站中的隐藏表单 -->
<form action="https://bank.com/transfer" method="POST" id="stealForm">
  <input type="hidden" name="to" value="attacker" />
  <input type="hidden" name="amount" value="10000" />
</form>
<script>document.getElementById('stealForm').submit();</script>

防御策略

1. CSRF Token

最有效的防御方案,核心原理:服务器生成随机Token,前端请求必须携带。

JavaScript
// 服务端生成Token(Node.js示例)
const crypto = require('crypto');

function generateCSRFToken() {
  return crypto.randomBytes(32).toString('hex');
}

// 存储Token并返回
app.get('/csrf-token', (req, res) => {
  const token = generateCSRFToken();
  req.session.csrfToken = token;
  res.json({ csrfToken: token });
});
JavaScript
// 前端请求携带Token
async function fetchWithCSRF(url, options = {}) {
  const { csrfToken } = await fetch('/csrf-token').then(r => r.json());

  return fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'X-CSRF-Token': csrfToken
    }
  });
}
JavaScript
// 服务端验证Token中间件
function csrfProtection(req, res, next) {
  const token = req.headers['x-csrf-token'];
  const sessionToken = req.session.csrfToken;

  if (!token || token !== sessionToken) {
    return res.status(403).json({ error: 'CSRF token验证失败' });
  }
  next();
}

app.post('/api/sensitive-action', csrfProtection, (req, res) => {
  // 处理敏感操作
});

2. SameSite Cookie属性

Cookie的SameSite属性限制跨站请求携带Cookie。

JavaScript
// 设置Cookie时指定SameSite
res.cookie('sessionId', sessionId, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict'  // 或 'lax'
});
SameSite值行为适用场景
strict完全禁止跨站发送高安全要求
lax允许GET链接跳转携带平衡安全与体验
none允许跨站发送(需配合secure)第三方集成

3. Referer检查

验证请求来源是否合法。

JavaScript
function checkReferer(req, res, next) {
  const referer = req.headers.referer || req.headers.referrer;

  if (!referer) {
    // 无Referer时的策略
    return res.status(403).json({ error: '缺少Referer' });
  }

  const allowedOrigins = ['https://myapp.com', 'https://www.myapp.com'];
  const refererOrigin = new URL(referer).origin;

  if (!allowedOrigins.includes(refererOrigin)) {
    return res.status(403).json({ error: '非法请求来源' });
  }

  next();
}

4. 双重Cookie验证

前端从Cookie读取Token并在请求中发送,服务端对比两者。

JavaScript
// 前端:从Cookie读取并放入请求头
function getCsrfFromCookie() {
  const match = document.cookie.match(/csrfToken=([^;]+)/);
  return match ? match[1] : null;
}

fetch('/api/action', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': getCsrfFromCookie()
  }
});
JavaScript
// 服务端:对比Cookie与请求头中的Token
function doubleCookieCSRF(req, res, next) {
  const cookieToken = req.cookies.csrfToken;
  const headerToken = req.headers['x-csrf-token'];

  if (!cookieToken || !headerToken || cookieToken !== headerToken) {
    return res.status(403).json({ error: 'CSRF验证失败' });
  }
  next();
}

前端框架集成

React示例

jsx
// CSRF Token Provider
import { createContext, useContext, useEffect, useState } from 'react';

const CSRFContext = createContext();

export function CSRFProvider({ children }) {
  const [csrfToken, setCsrfToken] = useState(null);

  useEffect(() => {
    fetch('/api/csrf-token')
      .then(r => r.json())
      .then(data => setCsrfToken(data.csrfToken));
  }, []);

  return (
    <CSRFContext.Provider value={csrfToken}>
      {children}
    </CSRFContext.Provider>
  );
}

// 使用
function useCSRF() {
  return useContext(CSRFContext);
}

Axios拦截器集成

JavaScript
import axios from 'axios';

const api = axios.create();

// 请求拦截器自动添加CSRF Token
api.interceptors.request.use(config => {
  const csrfToken = getCsrfFromCookie();
  if (csrfToken) {
    config.headers['X-CSRF-Token'] = csrfToken;
  }
  return config;
});

安全配置检查清单

JavaScript
// 完整安全配置示例
app.use(session({
  secret: process.env.SESSION_SECRET,
  cookie: {
    httpOnly: true,      // 防止XSS读取
    secure: true,        // 仅HTTPS传输
    sameSite: 'strict'   // CSRF防护
  }
}));

// 关键操作必须使用POST/PUT/DELETE
app.post('/api/transfer', csrfProtection, handleTransfer);

注意:GET请求不应执行状态变更操作,CSRF Token验证仅针对状态变更请求。

要点总结

方案安全性兼容性推荐程度
CSRF Token⭐⭐⭐⭐⭐
SameSite CookieIE不支持⭐⭐⭐⭐
Referer检查⭐⭐⭐
双重Cookie中高⭐⭐⭐⭐

核心原则

  • 所有状态变更请求必须验证CSRF Token
  • 优先使用SameSite=strict Cookie
  • 敏感操作增加二次确认
  • 定期审计安全配置

📝 发现内容有误?点击此处直接编辑

← 上一篇 跨站脚本攻击(XSS)防御
下一篇 → 输入验证与净化
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库