Skip to content

CSRF 跨站请求伪造

信息

跨站请求伪造通常缩写为 CSRF 或者 XSRF,是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。跟跨网站脚本 XSS 相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户浏览器的信任,浏览器对于同一 domain 下所有请求会自动携带 cookie

原理

  1. 用户 A 正常打开网站 B,并且成功登录获取 cookie
  2. 用户 A 未退出网站 B,在同一个浏览器中打开新的 TAB 访问了网站 C
  3. 网站 C 的页面存有一些攻击性的代码,会发出对于网站 B 的一个访问请求。
  4. 浏览器收到请求后,在用户不知情的情况下携带 cookie 访问网站 B,导致网站 B 以用户 A 的权限处理请求。

实例

小明在某银行有存款,通过 GET 表单请求 http://bank.example/withdraw?uid=1&amount=100&for=2 就可以向账户 2 转账 100,当对银行发起这个请求后,首先会验证 cookie 是否有合法的 session 才进行数据处理。

小黑近期无聊,就自己做了一个网站,利用某些标签允许跨域请求资源的策略,在自己的网站中构造 <img src="http://bank.example/withdraw?uid=1&amount=100&for=2">,并通过广告、游戏等方式诱导小明点击进入这个网站,此时浏览器会携带 cookie 访问银行网站。在大部分情况下,这个请求并不会成功被执行,因为他并没有小明的认证信息,但是如果此时恰好小明刚刚访问了银行,此时服务端 session 尚未过期,这个 url 就会被正常响应,转账就会被执行。

防御

验证码

对于敏感操作加入验证码,强制用户与网站进行交互,能很好遏制 CSRF 攻击。

避免使用 GET

GET 接口太容易被拿来做 CSRF 攻击,只要构造一个 <img> 标签,而 <img> 标签又是不能过滤的数据。接口最好限制为 POST 使用,GET 则无效,降低攻击风险。当然强制 POST 只是降低了风险,攻击者只要构造一个 <form> 就可以,但需要在第三方页面做,这样就增加暴露的可能性。

检查 Referer 字段

HTTP 协议有一个 Referer 字段,记录了该 HTTP 请求的来源地址,浏览器限制其改动,最多将其设置为空 rel="noreferrer",当然如果不是在浏览器中发起 HTTP 请求是可以随意改动这个字段的。

同样以小黑的 CSRF 攻击为例,假如小黑诱导小明的网站为 www.black.com,那么对于其构建的 CSRF 攻击请求的 Refererwww.black.com,而正常情况下应该为 http://bank.example 域名开头的一个链接,检测其不正确或者为空即拒绝响应。

但是这种方法也有一定的局限性,某些旧版本的浏览器比如 IE6 可以篡改 Referer 字段,有些用户认为 Referer 字段会侵犯他们的隐私,从而关闭了浏览器发送 Referer,正常访问网站会被误认为为 CSRF 而拒绝响应。

加入 Token 验证字段

CSRF 攻击之所以能够成功,是因为浏览器自动携带 cookie 进行请求,该请求中所有的用户验证信息都是存在于 cookie 中,由此可以完全伪造用户的请求。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。

在请求头中加入一个 Token 字段,浏览器并不会自动携带 Token 去请求,且 Token 可以携带一段加密的 jwt 用作身份认证,这样进行 CSRF 的时候仅传递了 cookie,并不能表明用户身份,网站即拒绝攻击请求。