vlambda博客
学习文章列表

跨站点请求伪造(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也会泄漏,所以安全防御的体系是相辅相成的。