🤔 当你用账号密码登录一个网站(比如你的邮箱)时,服务器会想:“好的,这个人是张三,密码对了。我不能让他每点一个链接都重新输一次密码,那太麻烦了。”
🤗 于是,服务器会给你的浏览器发一个独一无二的凭证,就像给你一个临时工牌。这个“工牌”在技术上的名字叫 Session ID(会话ID),浏览器会把它自动保存在一个叫 Cookie 的地方。
Cookie)一起带上。服务器看到这个工牌,就知道:“哦,是张三啊,请进请进。”这种“自动带工牌”的机制,带来了巨大的便利性,用户无需重复登录,可以无缝地浏览网页、收邮件、发状态。
下图是正常请求过程的时序图

但同时也埋下了巨大的风险——任何来源的请求,只要是你浏览器发往这个网站的,浏览器都会自动、无条件地把这个“工牌”带上。 这就导致出现了 CSRF 攻击!
黑客想冒充你,但他拿不到你的密码,也偷不走你浏览器里的那个“工牌”。但他想到了一个更狡猾的办法:
他不需要偷走工牌,他只需要骗你帮他把一个“指令”递进去就行了。
我们来分解一下他的操作:
伪造指令:黑客研究你想攻击的网站(比如银行网站)的转账功能。他写了一个转账请求,命令是“从张三的账户转100元到李四(黑客的)账户”。
设计陷阱:他把这个转账请求伪装成一个看起来人畜无害的东西,比如:一个“点击抽大奖”的按钮;或者一个隐藏的iframe,你进入页面就自动触发。
诱你上钩:他想办法让你去访问这个藏有陷阱的网页(比如通过邮件、论坛发链接给你)。
触发请求:你一旦点击那个按钮(或者只是访问了那个页面),你的浏览器就会向银行网站发送那个早已准备好的转账请求。
自动认证:关键是,如果你之前已经登录了银行网站,你的浏览器在发送这个请求时,会习惯性地、自动地把你登录银行的“工牌”(Cookie)也一起附带上!
攻击成功:银行的服务器收到了这个请求,一看:“工牌是对的,是张三本人发来的请求。好的,执行转账!”于是,钱就在你完全不知情的情况下转走了。
这个过程就叫做跨站请求伪造:

📖 原理:利用 <img>、<script> 等标签的 src 属性自动发起 GET 请求。
🌰 示例
用户访问含此代码的恶意页面时,自动触发转账(需用户已登录银行)。
📖 原理:构造隐藏表单,通过 JS 脚本自动提交
🌰 示例:
用户访问页面时自动提交表单,修改密码。
原理:结合 CORS 配置漏洞或 JSONP 回调函数,伪造 JSON 请求。
示例:
窃取API返回的敏感数据。
📖 原理:在论坛/CMS中植入恶意代码(如自动提交表单的图片),用户浏览即触发。
⚠ 危害:结合 XSS 可大规模传播(如自动向好友发送恶意链接)。
原理:为每个用户会话生成唯一令牌(Token),要求客户端在发起敏感请求时提交该令牌,服务器验证其有效性。
实现方式:
生成与存储:用户访问页面时,服务器生成高强度随机Token(如32位随机字节),存储在服务端Session或加密Cookie中。
嵌入客户端:
✌🏻 表单:将 Token 放入隐藏字段(<input type="hidden" name="csrf_token" value="...">)。
😃 AJAX请求:将 Token 添加到请求头(如X-CSRF-Token)。
校验与更新:
✌🏻 服务器收到请求后,对比客户端提交的Token与Session中存储的是否一致,不一致则拒绝
🤔 每次验证后更新 Token(避免重放攻击)
关键注意事项:
原理:限制浏览器在跨站请求中自动发送Cookie,从而阻断恶意请求的身份认证
实现方式(HTTP响应头中设置):
Cookie(适用于敏感操作如支付)Cookie,但阻止 POST、iframe等非安全请求局限性:
原理:校验 HTTP 请求头中的 Referer 或 Origin 字段,确保请求来自合法域名
优先级:
Origin 头(仅含协议+域名+端口,无路径,隐私性更好)Referer 为空或不匹配时拒绝请求缺陷:
RefererJWT 存储于前端
若 JWT 存储在 localStorage 而非 Cookie,并通过 Authorization: Bearer <token> 手动添加请求头,浏览器不会自动携带,天然免疫 CSRF。
OAuth 2.0 的授权机制
依赖 state 参数和 PKCE 流程,验证请求来源合法性,间接防御 CSRF
关键操作二次验证
验证码(CAPTCHA):敏感操作(如转账、改密码)前强制用户输入图形/短信验证码。
密码确认:执行操作前要求再次输入密码。 ✅ 适用场景:高风险操作,但需平衡用户体验。
限制 HTTP 方法
强制敏感操作(如修改数据、转账等操作)使用POST/PUT/DELETE,禁用GET(避免通过 <img> 标签触发)。
因为 CSRF 本质是利用浏览器自动带 Cookie 的机制。如果把 Token 放在 Header (Authorization 或 X-CSRF-Token),因为浏览器默认不会自动携带这种自定义 Header (除非是同源 AJAX),攻击者很难通过简单的 <img> 或 <form> 伪造这种请求。
因为如果使用 JWT (JSON Web Token) 并存放在 localStorage (或者 HttpOnly Cookie + CSRF Token),且每次请求都通过 Authorization Header 手动携带 Token,那么 CSRF 就很难发生了 (因为攻击者即使诱导你发请求,浏览器也不会自动带上 Header 中的 Token)。
CSRF 攻击的根源在于Web身份验证机制的缺陷:
本质矛盾:服务器信任“携带Cookie的请求=用户自愿操作”,但实际可能是恶意诱导的“借刀杀人”。