跨站点请求伪造(CSRF)
CSRF(Cross Site Request Forgery),跨站点请求伪造。
一个例子
攻击者首先在自己的域构造一个页面
http://www.a.com/csrf.html
其内容为
<img src="http://blog.com/article?m=delete&id=1" />
攻击者诱使目标用户(博主),访问这个页面,id=1的一篇博客文章就被删除了。
这里攻击者以该用户身份(本质上是发送了Cookie)在第三方站点里发送了请求,这个请求是攻击者伪造的,所以叫"跨站点请求伪造"。
浏览器的Cookie策略
浏览器所持有的Cookie分为两种:
一种是"Session Cookie",又称"临时Cookie";另一种是"Third-party Cookie",也称为"本地Cookie"。Third-party Cookie服务器指定了Expire时间,会保存在本地。Session Cookie没有指定Expire时间,保存在浏览器进程的内存空间中,新打开的Tab页也是有效的,但浏览器关闭后就失效了。
一个域加载另一个域的资源(比如使用img、iframe、script、link等标签),由于安全原因,许多浏览器会阻止Third-party Cookie的发送,只能发送Session Cookie。而某些浏览器不会阻止,前面删除文章的例子就是在不会阻止Third-party Cookie发送的浏览器中实现的。
P3P头的副作用
浏览器拦截第三方Cookie发送,在某种程度上降低了CSRF攻击的威力。
但是P3P Header会是问题复杂起来,它是W3C制定的一项关于隐私的标准,如果网站返回给浏览器的HTTP头中包含有P3P头,将允许浏览器发送第三方Cookie。它主要用于需要跨域访问页面的场景,如父页面b嵌入了iframe,iframe的src指向的a页面网址,a页面响应头有Set-Cookie。一般情况下由于跨域,在a.com上Set-Cookie是不会成功的,但是加入P3P头后,可以跨域Set-Cookie成功,浏览器也不会再拦截第三方Cookie的发送。P3P头只需要由网站设置一次即可,之后每次请求都会遵循此策略。
只有GET请求可以吗?
对于攻击者来说,有许多方法构造POST请求。
1.form表单
在页面中构造一个form表单,使用JavaScript自动提交这个表单。
2.Flash
Flash有多种方式能够发送网络请求,包括POST请求,如使用URLRequest、getURL、loadVars等。
CSRF Worm
2008年9月,国内安全组织80sec公布了一个百度的CSRF Worm。
它主要利用了两个接口:
http://msg.baidu.com/?...sn=用户账户&co=消息内容...
修改参数sn,可以对指定用户发送短消息。
而另一个接口能查询出某个用户的所有好友
http://frd.baidu.com/?...un=用户账户...
两者相结合,先让一个百度用户查看恶意页面后,给他所有好友发送一条短消息,消息中又包含一个恶意页面,使得好友将消息发送给他们的好友,就形成了一个CSRF Worm。
CSRF的防御
验证码
验证码可以强制用户与应用进行交互,只有在用户知情的情况下才会发送请求。但是,出于用户体验考虑,不能给所有接口都加上验证码,所以只能作为一种辅助的防御手段。
Referer Check
Referer的值一般是请求所在的页面,Referer Check可以被用于检查请求是否来自合法的”源“。
但是,服务器并非任何时候都可以取到Referer,很多用户处于隐私保护限制了Referer的发送。从Https跳转到http出于安全的考虑,浏览器也不会发送Referer。Flash一些低版本也可以伪造Referer。
所以不能依赖Referer来防御,但作为监控CSRF攻击的发生,倒是一种可行的方法。
Anti CSRF Token
这是业内的常用做法。
CSRF的本质是重要操作的所有参数都是可以被攻击者猜测到的。
我们在参数上增加一个参数Token,这个Token是随机的,Token可以放在用户的Session中,或者浏览器的Cookie中,在提交请求时,服务器需要验证请求的Token和用户的Session(或Cookie)是否一致,如果一致,则请求是合法的。
这是“不可预测性原则”的一种应用。
Token的使用原则
1.Token的生成一定要足够随机。
2.可以允许在一个用户的有效生命周期内,使用同一个Token。但如果是下个周期,则应该生成新的Token(如表单已提交)。
3.为了处理多个页面共存Token失效的问题,可以考虑生成多个有效的Token。
4.要注意Token的保密性,可以把Token放在表单内部,而非url上,把敏感操作由GET改为POST,避免Token泄漏。当然如果网站存在XSS漏洞,Token也会泄漏,所以安全防御的体系是相辅相成的。