一张图彻底搞懂CSRF
CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种经典的 Web 安全漏洞。CSRF 攻击利用了用户在已认证的站点上的身份,诱使用户在不知情的情况下执行恶意操作。攻击者通常通过构造恶意链接或表单,诱导用户点击或提交,从而在用户不知情的情况下发送请求到受信任的网站。

CSRF 攻击原理
CSRF 攻击的基本原理是利用用户在受信任网站上的身份认证状态。当用户登录某个网站并获得身份验证后,浏览器会存储相关的 Cookie 或会话信息。攻击者通过诱导用户访问恶意网站,利用浏览器自动携带的身份认证信息,向受信任的网站发送伪造的请求。这些请求看起来像是用户自己发起的,因此受信任的网站会执行相应的操作。我们可以把 CSRF 形象地理解为:“借你的手,办他的事。”
CSRF 攻击的发生过程
CSRF 能够成功的核心前提是:浏览器在发送请求时,会自动带上目标网站的 Cookie。
以下是一个典型的攻击流程:
- 受害者登录: 你登录了银行网站
Bank.com,并在本地浏览器留下了登录态(Session Cookie)。 - 受害者访问恶意网站: 在没有退出登录的情况下,你被诱导点击了一个链接或进入了黑客控制的恶意网站
Evil.com。 - 发送伪造请求:
Evil.com页面中隐藏了一段代码(可能是个自动提交的表单,或者一个隐藏的图片标签),它会指向Bank.com的转账接口:http://Bank.com/transfer?to=hacker&amount=10000。 - 浏览器自动配合: 当你的浏览器去请求
Bank.com时,它会发现“哦,我有这个网站的 Cookie”,于是自动把你的登录凭证带上了。 - 服务器误判: 银行服务器收到了请求,验证了 Cookie 发现确实是你,于是执行了转账操作。
CSRF为什么能成功?
CSRF 的成功主要利用了两个弱点:
- 浏览器的自动机制: 只要域名匹配,浏览器发送请求时会自动携带该域名的 Cookie。它无法区分这个请求是你在
Bank.com页面上点下的,还是在Evil.com页面里被代码触发的。 - 缺乏请求来源验证: 许多网站没有对请求的来源进行严格验证,导致服务器无法区分合法请求和伪造请求。
攻击的局限性
虽然 CSRF 很危险,但它也有明显的局限:
- 需要用户在线: 受害者必须处于登录状态,且 Cookie 尚未过期。
- 需要预知接口: 攻击者必须事先知道目标网站的接口细节(例如 URL、参数名)。如果接口参数包含不可预测的随机值,攻击就很难奏效。
- 看不见结果: 攻击者只能“发起”请求,也即是 “Fire and Forget”。由于浏览器的“同源策略”(Same-Origin Policy),攻击者无法跨域读取
Bank.com返回的响应内容(他拿不到你的余额)。
如何防御 CSRF?
知道了 CSRF 的原理和局限性后,我们就可以针对性地采取多种措施来防御这种攻击。
- SameSite Cookie:通过设置 Cookie 的
SameSite属性为Strict或Lax,可以限制浏览器在跨站请求时发送 Cookie,从而防止 CSRF 攻击。 - Anti-CSRF Token:服务器在返回的页面表单中嵌入一个随机生成的、不可预测的Token(通常与用户会话关联)。当提交表单(如转账)时,必须携带这个Token供服务器验证。攻击者无法预知这个 Token,因此无法伪造有效请求。
例如在ASP.NET MVC中,可以使用
@Html.AntiForgeryToken()生成Token,并在控制器中使用[ValidateAntiForgeryToken]属性进行验证。 - 验证 Referer/Origin:服务器检查请求的
Referer或Origin头,确保请求来源于受信任的域名,否则拒绝请求。 - 二次验证:对于敏感操作(如转账、修改密码),要求用户进行额外的验证步骤,如输入验证码或支付密码。
- 避免使用 GET 请求进行状态更改:确保所有会修改服务器状态的操作(如转账、删除)都使用 POST、PUT 或 DELETE 请求,而不是 GET 请求。因为 GET 请求更容易被 CSRF 利用。
- 不使用 Cookie 进行身份验证:采用基于 Token 的身份验证(如 JWT),并将 Token 存储在浏览器的
localStorage或sessionStorage中,而不是 Cookie 中。这样,跨站请求时不会自动携带身份验证信息。这种做法对 CSRF 攻击有天然免疫力。但需要警惕另一个主要威胁:跨站脚本攻击(XSS)。
通过以上多种防御措施的结合使用,可以有效降低 CSRF 攻击的风险,保护用户的账户安全和数据完整性。
总结
CSRF 利用了服务器对浏览器(Cookie)的盲目信任以及浏览器会自动在发往目标网站的请求中附上用户的认证凭证。现在的浏览器默认行为(如 Chrome 的 SameSite 默认限制)已经让简单的 CSRF 攻击变得越来越难,但在开发接口时,依然必须保持警惕。