适用场景
CSRF 攻击防御适用于所有基于 Cookie 会话的 Web 应用,包括管理后台、支付回调、用户资料修改等高风险操作。当应用仅依赖 Cookie 鉴权且无防护机制时,攻击者可诱导已登录用户发起恶意请求,造成改密、越权操作或数据篡改。本教程适用于 PHP/Java/Python 等主流 Web 应用及 Nginx 反向代理环境。
前置条件
- 已部署的 Web 应用(示例基于 PHP + Nginx)
- 服务器 root 权限(用于修改 Nginx 配置)
- 应用支持 Session 与 Cookie 机制
原理说明
CSRF 攻击利用浏览器自动携带 Cookie 的特性:用户访问恶意页面时,页面中的表单或图片请求会自动携带目标站点的会话 Cookie,服务端无法区分请求是否由用户主动发起。防御核心是让服务端能够验证请求”来源可信”,常见手段包括同步 Token 校验、SameSite Cookie 属性、Referer 来源校验。同步 Token 是业界首选方案,因为它不依赖浏览器行为,兼容性最好。
操作步骤
第一步:应用层引入 CSRF Token
在表单中嵌入随机 Token 并存入 Session,提交时用 hash_equals 恒定时间比对:
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')) {
http_response_code(403);
exit('CSRF 校验失败');
}
}
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
?>
表单中输出隐藏字段:<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
第二步:设置 SameSite Cookie
setcookie('session_id', $sid, [
'httponly' => true,
'samesite' => 'Lax',
'secure' => true
]);
SameSite=Lax 阻止跨站请求携带 Cookie,Secure 强制 HTTPS 传输,HttpOnly 防 XSS 窃取。
第三步:Nginx 层校验 Referer(纵深防御)
location ~ ^/(admin|api)/ {
if ($http_referer !~ "^https?://(www\.)?example\.com/") {
return 403;
}
proxy_pass http://127.0.0.1:8080;
}
注意:仅校验 Referer 不足以防御(空 Referer 或同源 XSS 可绕过),必须与 Token 配合使用。
第四步:关键操作二次校验
对改密、删除等敏感操作增加二次确认(验证码或再次输入密码),进一步缩小攻击面。
配置验证
- 正常流程:登录后提交表单,返回 200
- 篡改 Token:手动修改表单 Token 值提交,应返回 403
- 跨站模拟:
curl -X POST https://example.com/admin/delete -H "Referer: https://evil.com",应返回 403 - 检查响应头 Set-Cookie 是否包含
SameSite=Lax属性
常见问题
Q1:Token 校验会影响所有 POST 请求吗?
只影响启用校验的接口。建议对登录后所有写操作统一校验,GET 请求无需校验但不得执行状态修改。
Q2:前后端分离(SPA + API)如何防 CSRF?
使用 Authorization 请求头携带令牌(非 Cookie)即可天然免疫;若必须使用 Cookie,需配合 SameSite=Strict 或自定义请求头校验。
Q3:Nginx Referer 校验误伤合法请求怎么办?
只对写操作(POST/PUT/DELETE)与后台路径启用校验,GET 与静态资源不校验;同域多站点场景需在白名单中补充所有可信域名。
总结
CSRF 防御需分层实施:应用层同步 Token是根基,SameSite Cookie提供浏览器级兜底,Nginx Referer 校验作为纵深防御。三者结合可覆盖绝大多数 CSRF 攻击场景,建议在生产环境逐步启用并配合自动化安全测试回归验证。