CSRF 攻击的典型场景
CSRF(Cross-Site Request Forgery)攻击是一种利用用户已登录的身份,在用户不知情的情况下执行非预期操作的攻击方式。攻击者通过伪造请求,诱骗用户或浏览器发送恶意请求,从而绕过身份验证机制。
CSRF 攻击的基本原理
CSRF 攻击的核心是利用浏览器的自动携带 Cookie 机制。当用户登录某个网站后,浏览器会存储会话 Cookie,并在后续请求中自动附加这些 Cookie。攻击者通过构造一个恶意页面或链接,诱导用户访问,从而触发一个跨站请求。由于请求携带了用户的合法 Cookie,服务器会误认为是用户主动发起的操作。
典型的攻击流程如下:
- 用户登录可信网站 A,并保存了会话 Cookie。
- 用户未退出登录的情况下访问恶意网站 B。
- 网站 B 的页面中包含一个向网站 A 发起请求的代码(如表单或脚本)。
- 浏览器自动携带网站 A 的 Cookie 发送请求,网站 A 服务器认为这是用户合法操作。
典型攻击场景示例
场景一:通过 GET 请求修改数据
假设一个银行网站的转账功能使用 GET 请求实现,URL 如下:
https://bank.example/transfer?to=attacker&amount=1000
攻击者可以在恶意网站中嵌入一个图片标签:
<img src="https://bank.example/transfer?to=attacker&amount=1000" width="0" height="0">
当用户访问该页面时,浏览器会自动加载图片,并发送 GET 请求完成转账。
场景二:通过表单提交伪造请求
如果银行改用 POST 请求,但未防护 CSRF,攻击者可构造一个隐藏表单:
<form action="https://bank.example/transfer" method="POST">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="1000">
</form>
<script>document.forms[0].submit();</script>
用户访问页面时,表单会自动提交。
场景三:利用 JSON API 的 CSRF
现代应用常用 JSON API,但若未正确配置 CORS,仍可能被攻击。例如:
fetch('https://api.example/change-email', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'attacker@example.com' }),
credentials: 'include' // 自动携带 Cookie
});
攻击者可通过恶意页面直接发送该请求。
高危操作与敏感接口
以下类型的接口极易成为 CSRF 攻击目标:
- 修改用户信息(密码、邮箱、手机号)
- 资金操作(转账、支付)
- 数据删除(清空购物车、删除账号)
- 权限变更(提升用户角色)
例如,社交网站的“删除账号”接口:
POST /api/account/delete HTTP/1.1
只需一个简单的伪造请求即可导致账号被删。
防御措施的实现细节
同源检测:Origin 与 Referer 校验
服务器端应验证请求头中的 Origin
或 Referer
:
// Node.js 示例
app.post('/transfer', (req, res) => {
const origin = req.get('Origin');
if (origin !== 'https://yourdomain.com') {
return res.status(403).send('Forbidden');
}
// 处理正常逻辑
});
CSRF Token 机制
- 生成 Token:
// 服务端生成并存储 Token
const csrfToken = crypto.randomBytes(32).toString('hex');
session.csrfToken = csrfToken;
- 前端携带 Token:
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<!-- 其他表单字段 -->
</form>
- 服务端验证:
app.post('/transfer', (req, res) => {
if (req.body._csrf !== session.csrfToken) {
return res.status(403).send('Invalid CSRF token');
}
// 处理正常逻辑
});
SameSite Cookie 属性
设置敏感 Cookie 的 SameSite
属性:
Set-Cookie: sessionId=abc123; SameSite=Strict; Secure; HttpOnly
Strict
:完全禁止第三方 CookieLax
:允许安全方法(如 GET)的跨站请求
双重 Cookie 验证
- 前端从 Cookie 读取 token:
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
const csrfToken = getCookie('csrfToken');
- 在请求头中附加:
fetch('/api/transfer', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrfToken
}
});
框架内置防护机制
Express 的 csrf 中间件
const csrf = require('csurf');
app.use(csrf({ cookie: true }));
// 在视图中注入 token
app.get('/form', (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
Django 的 CSRF 防护
模板中自动添加 token:
<form method="post">
{% csrf_token %}
<!-- 表单内容 -->
</form>
Spring Security 配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
特殊场景下的防护
单页应用(SPA)的 CSRF 防护
对于前后端分离架构:
- 服务端设置
SameSite=Lax
的 Cookie - 前端从首次响应中获取 CSRF Token:
// 登录响应示例
{
"user": {...},
"csrfToken": "a1b2c3d4"
}
- 后续请求在 Header 中携带:
axios.defaults.headers.common['X-CSRF-Token'] = storedCsrfToken;
文件上传的 CSRF 防护
传统表单上传需特殊处理:
<form enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="token">
<input type="file" name="file">
</form>
防御措施的局限性
- Token 泄露:若存在 XSS 漏洞,攻击者可窃取 Token
- 子域名风险:同站但不同子域可能共享 Cookie
- 浏览器兼容性:旧版浏览器可能不支持 SameSite
实际案例分析
案例 1:社交媒体关注劫持
某平台关注 API 未防护 CSRF:
POST /api/follow HTTP/1.1
Host: social.example
Cookie: session=valid_session
{"userId":"attacker"}
攻击者构造页面自动发送该请求,导致用户关注恶意账号。
案例 2:电商平台价格篡改
商品修改接口缺少防护:
fetch('/admin/products/123', {
method: 'PUT',
body: JSON.stringify({ price: 0.01 })
});
攻击者可诱骗管理员访问恶意页面篡改商品价格。
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:CSRF 攻击的基本原理
下一篇:CSRF 与 XSS 的区别