CSRF 是指在保持登录的状态下,只是打开了另一个站点,转账或修改设置就在你不知情时被执行。本文讲解其原理以及可靠的防范方法(不会写出攻击步骤)。
为什么能成立(原理)
浏览器在向某个站点发起请求时,会自动附带该站点的 Cookie。因此,只要用户正登录着银行站点,即便是从另一个恶意页面向银行发出操作请求,浏览器也会把「本人的 Cookie」一并发出去。从服务器看来,这与本人的正规操作毫无区别。
XSS 是「让代码在受害者的浏览器中运行」,而 CSRF 是「擅自借用受害者的登录状态」的攻击(→ XSS 是什么)。
防御
强制要求 CSRF Token
对改变状态的操作(表单提交、API)要求一个无法猜测的一次性 Token。由服务器签发,请求中若不包含它则拒绝。许多框架都内置提供。
设置 SameSite Cookie
给会话 Cookie 加上 SameSite=Lax(或 Strict),不让源自其他站点的请求附带 Cookie。近年的默认值是 Lax,仅此一项就能起到很大作用。
不用 GET 来改变状态
设计上让浏览(GET)不产生副作用。变更一律用 POST/PUT/DELETE,并通过 Token 校验。
校验 Origin / Referer
对重要操作,在服务器端确认请求来源(Origin)是否为本站,拒绝外部来源。
本站观点:几乎已「解决」但仍不可大意
凭借现代框架的 CSRF Token+浏览器的 SameSite=Lax 默认值,典型的 CSRF 已大幅减少。话虽如此,在自行实现的 API、老旧结构、省去了 Token 的管理后台中,它至今仍会发生。即使「全权交给框架」,也最好亲自确认一次改变状态的路径上是否都通过了 Token 校验。
常见的漏洞缝隙
即便了解原理,在实现中也容易在以下两点出现疏漏。
- 让 GET 带有副作用:如果设计成用于浏览的 GET 会改变状态,那么仅凭一个图片标签或一条普通链接就可能让 CSRF 成立。改变状态务必使用 POST/PUT/DELETE,并通过 Token 校验。
- 只有部分路径忘了做 Token 校验:在后来追加的 API 或管理功能中,常常会漏掉 Token 校验。不要因「已交给框架」就放心,请把所有改变状态的路径清点一遍。
CSRF、XSS 与 SSRF 的区别
这三个名字相近的攻击,可以按「谁发出请求」和「利用了什么」来区分。
| 攻击 | 谁发出请求 | 利用了什么 | 主要防御 |
|---|---|---|---|
| CSRF | 用户的浏览器(用户本人不知情) | 浏览器自动附带 Cookie | CSRF Token、SameSite Cookie |
| XSS | 在用户浏览器中运行的攻击者脚本 | 渲染页面时缺少转义 | 输出时转义、CSP |
| SSRF | 你的服务器 | 按给定 URL 去获取内容的功能 | 目标白名单、阻止内部地址 |
CSRF 和 XSS 都经由用户的浏览器发挥作用。但如果页面存在 XSS,页面内的脚本就能读取 CSRF Token,CSRF 防御也就被绕过了。CSRF 防护以 XSS 已被处理为前提。
实例:伪造的投稿被当作本人所为
2012 年,有人通过横滨市网站的意见表单发布了袭击小学的恐吓内容。看起来像是发送源的电脑的主人被逮捕,后来查明这是一起误捕。据日本媒体报道,同年 12 月东京警方说明,这条投稿是利用 CSRF 发出的:访客打开了留言板上贴出的链接后,其浏览器被诱使提交了该内容。
由此可以得出两点教训。
- CSRF 请求看起来和本人发出的完全一样:服务器只能看到用户的 IP 地址和 Cookie。仅凭日志,无法判断是用户本人发送的,还是被诱使发送的。
- 不需要登录的表单同样在范围内:那个意见表单并不需要登录。凡是不希望被他人触发的提交(投稿、申请、举报),无论是否需要登录,都应加上 Token。
CSRF 至今仍是常见的弱点。在 MITRE 于 2025 年 12 月发布的「CWE Top 25」(最危险的 25 种软件弱点)中,CSRF(CWE-352)位列第三。
检查自己网站的方法
给会话 Cookie 明确设置 SameSite
在浏览器开发者工具(Application → Cookies)中,或用网站综合安全诊断,检查会话 Cookie 的 SameSite 属性。Chrome 和 Edge 会把未设置该属性的 Cookie 当作 Lax 处理,但 Safari 和 Firefox 默认并不这样做。不要依赖浏览器默认值,请自己设置 SameSite=Lax 或 Strict。
检查 CSRF 豁免设置
确认框架的 CSRF 防护是否在某些路由上被关闭(Django 的 csrf_exempt、Laravel 的例外列表、Rails 的 skip_forgery_protection 等)。如果确有理由关闭,例如 Webhook 接收端,请改用签名校验来保护该路由。
找出会改变状态的 GET 路由
逐一检查路由列表,找出执行删除、更新或登出的 GET 路由。把它们改为 POST 等方法,并通过 Token 校验。
为重要操作再加一道确认
修改密码或邮箱地址、转账、授予权限时,在 Token 之外再要求输入当前密码或进行多因素认证。即使请求被伪造,这一步用户确认也能将其拦下。
参考资料(一手来源)
- OWASP, "Cross-Site Request Forgery Prevention Cheat Sheet" — cheatsheetseries.owasp.org(Token、Sec-Fetch-Site、SameSite 的局限、XSS 绕过 CSRF 防御、不用 GET 改变状态)
- MITRE, "2025 CWE Top 25 Most Dangerous Software Weaknesses"(2025 年 12 月)— cwe.mitre.org(CWE-352 位列第三)
- web.dev, "SameSite cookies explained" — web.dev(哪些浏览器把未设置该属性的 Cookie 当作 Lax)
- INTERNET Watch「遠隔操作事件『どんな些細なことでも』、CSRFのリンク踏んだ人は情報提供を」(2012 年 12 月 14 日,日语)— internet.watch.impress.co.jp(警方关于横滨市投稿使用了 CSRF 的说明)
- @IT「『なりすまし』ウイルスとクロスサイトリクエストフォージェリ(CSRF)による誤認逮捕について」(2012 年 11 月,日语)— atmarkit.itmedia.co.jp
- IPA「安全なウェブサイトの作り方」(日语)— ipa.go.jp