CSRF 跨站请求伪造
信息
跨站请求伪造通常缩写为 CSRF
或者 XSRF
,是一种挟制用户在当前已登录的 Web
应用程序上执行非本意的操作的攻击方法。跟跨网站脚本 XSS
相比,XSS
利用的是用户对指定网站的信任,CSRF
利用的是网站对用户浏览器的信任,浏览器对于同一 domain
下所有请求会自动携带 cookie
。
原理
- 用户
A
正常打开网站B
,并且成功登录获取cookie
。 - 用户
A
未退出网站B
,在同一个浏览器中打开新的TAB
访问了网站C
。 - 网站
C
的页面存有一些攻击性的代码,会发出对于网站B
的一个访问请求。 - 浏览器收到请求后,在用户不知情的情况下携带
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
攻击请求的 Referer
为 www.black.com
,而正常情况下应该为 http://bank.example
域名开头的一个链接,检测其不正确或者为空即拒绝响应。
但是这种方法也有一定的局限性,某些旧版本的浏览器比如 IE6
可以篡改 Referer
字段,有些用户认为 Referer
字段会侵犯他们的隐私,从而关闭了浏览器发送 Referer
,正常访问网站会被误认为为 CSRF
而拒绝响应。
加入 Token 验证字段
CSRF
攻击之所以能够成功,是因为浏览器自动携带 cookie
进行请求,该请求中所有的用户验证信息都是存在于 cookie
中,由此可以完全伪造用户的请求。要抵御 CSRF
,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie
之中。
在请求头中加入一个 Token
字段,浏览器并不会自动携带 Token
去请求,且 Token
可以携带一段加密的 jwt
用作身份认证,这样进行 CSRF
的时候仅传递了 cookie
,并不能表明用户身份,网站即拒绝攻击请求。