













CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种利用用户已登录身份,在用户不知情下执行非本意操作的攻击方式。常被戏称为"沉睡的间谍"或"骑在用户会话上的攻击"。
CSRF攻击能够成功,需要同时满足以下三个条件:
假设某银行的转账接口是:
POST /transfer
参数:toAccount=目标账户&amount=金额
正常流程:用户在银行网站填写表单 → 点击"转账" → 浏览器带上用户的Cookie发送请求。
CSRF攻击流程:
<!-- 恶意网站 evil.com 上的代码 -->
<img src="https://bank.com/transfer?toAccount=attacker&amount=10000" style="display:none">
bank.com 的Cookie → 发送转账请求。| 攻击方式 | 原理 | 典型场景 |
|---|---|---|
| GET型 | 恶意链接或图片自动触发GET请求 | <img src="https://target.com/delete?id=123"> |
| POST型 | 自动提交隐藏表单或Ajax请求 | <form action="https://target.com/changeEmail" method="POST"> 自动提交 |
| JSON型 | 利用JavaScript发送JSON格式的API请求 | 通过fetch或XMLHttpRequest自动发送 |
| 维度 | CSRF | XSS |
|---|---|---|
| 本质 | 利用身份认证机制的漏洞 | 利用用户输入输出的漏洞 |
| 是否需要用户执行代码 | 需要用户点击恶意链接/访问恶意网站 | 目标网站自己执行了恶意代码 |
| 与目标网站关系 | 利用目标网站对请求来源的信任 | 利用目标网站对用户输入的信任 |
| 是否需要注入脚本 | 不需要,攻击代码在第三方网站 | 需要,代码注入到目标网站 |
| 防范难度 | 相对容易(参考下文) | 较难(需要全面过滤) |
一句话总结:
服务器生成一个随机的、不可预测的Token,嵌入到表单或请求头中,服务器验证必须携带正确的Token。
<!-- 服务器返回的页面包含Token -->
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="random_token_abc123">
转账金额: <input type="text" name="amount">
</form>
工作流程:
优点:攻击者无法获取该Token(因为同源策略限制,恶意网站无法读取目标网站的页面源码)。
缺点:需要所有修改状态的操作都嵌入Token,实现成本稍高。
设置Cookie的SameSite属性,限制第三方域名发起的请求携带Cookie。
Set-Cookie: session_id=xyz123; SameSite=Lax; Secure; HttpOnly
SameSite取值:
Strict:任何跨站请求都不带Cookie(最安全,但可能影响正常的外链跳转)。Lax:顶级导航(如点击链接)带Cookie,但POST表单、iframe、img等不带(推荐)。None:跨站请求也带Cookie,但必须同时设置Secure(仅HTTPS)。优点:无需修改后端代码,配置简单,兼容主流现代浏览器(除IE外)。
缺点:旧浏览器不支持(如IE 11)。
检查请求头中的Referer或Origin是否与当前站点域一致。
def is_valid_request(request):
referer = request.headers.get('Referer')
if not referer:
return False
return referer.startswith('https://yourdomain.com')
优点:实现简单,无需额外存储。
缺点:某些场景下Referer可能缺失(如HTTPS到HTTP、用户隐私设置),部分低版本浏览器可伪造。
对于敏感操作(修改密码、转账、手机解绑等),要求用户重新输入密码/短信验证码/图形验证码。
举例:网银转账超过一定金额,必须输入短信验证码。
优点:彻底防御CSRF,即使Token泄露也无法绕过。
缺点:影响用户体验,仅适用于高敏感操作。
要求所有API请求必须携带一个自定义Header(如X-Requested-With: XMLHttpRequest),因为跨域请求无法设置自定义Header(除非CORS明确允许)。
// 前端Ajax请求自动添加
fetch('/transfer', {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
注意:这要求所有请求都是Ajax方式,传统表单提交不适用。
POST请求就认为安全(攻击者同样可以伪造POST表单)。验证码防御所有请求(体验差,不适合每个操作)。SameSite能100%防御(旧浏览器不支持,且仅限制Cookie携带,无法防御已窃取到Token的场景)。CsrfViewMiddleware(默认开启)CsrfFilter(默认开启)csurf 中间件VerifyCsrfToken 中间件如果你需要某段具体的防御代码示例(比如用Python Flask或Java Spring实现CSRF Token),可以告诉我,我为你写一个可以直接运行的demo。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。