JSONP注入利用与防御

JSONP基础

JSONP(JSON with Padding) 其目的是为了绕过诸如同源策略强制执行XMLHttpRequest(AJAX requests)去请求JSON数据。举个例子:

网站A: www.competition.com 提供赛事信息 其接口 competition.com/data.jsonjson格式返回了赛事数据,其分析子站B: analysis.competition.com 根据赛事信息进行分析 并展示给用户

那么B站的ajax想要获取data怎么做?

答案是很困难的,普通的ajax是无法完成的

因为ajax遵守同源策略,A、B是异源,异源资源共享通常是不允许的(除了脚本、链接等 详情可以看同源策略这篇文章)

那么怎么办呢?

我们可以发现,同源策略是允许跨域加载脚本的,我们的思路就是把数据放进js文件中,由于跨域脚本嵌入是可行的,从而跨域加载数据,但直接把json数据方式js文件格式是不正确的,我们的思路是设置一个函数调用,把json数据作为实参传递进来,然后在B中对形参进行处理,这样就跨域获取到了json数据。即script标签不受同源安全策略限制,它可以向别的域发送get请求。

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
我们要在B站请求A站这个json数据:
{"id" : "1","name" : "隔壁老王"}
那么我们在A站www.competition.com/data.js内容如下:
callback({"id" : "1","name" : "隔壁老王"});
由此,只需要在B站加载此js,然后构造此函数的处理即可:
function callback(data){
alert(data.name);
}
如果A站要根据需要同时提供不同的json数据,硬编码或每一个都写成一个js是肯定不行的,这时候可以将需求作为参数传递过去。

我们以程序员的角度来考虑,整个系统应该怎么编写,这样可以更好的帮助我们理解数据交换流程:
首先,定义一个用于接收数据的回调函数:

1
2
3
function myData(data) {
console.log(' DATA: ', data);
}

然后我们用<script>标签去跨域请求数据:

1
<script src="http://root.cool/userinfo?fn=myData"></script>

当获取完如上url的内容后,会自动解释成js代码执行。由此来看,以上url访问输出的结果类似如下:

1
myData([{nickname: 'empty_xl', blog: 'https://hellohxk.com'}])

一般后台会根据fn参数返回相应名称的函数,类似下面的方式:

1
2
3
4
5
<?php
//getUsers.php
$callback = $_GET['callback'];
print $callback.'({"nickname" : "1","blog" : "https://hellohxk.com"});';
?>

JSONP 利用

JSON劫持

JSON Hijacking 其实属于CSRF攻击的范围,当某网站使用JSONP传递敏感数据的时候,攻击者可以构造恶意JSONP调用界面,诱导被攻击者访问。

当我们找到一个jsonp接口且返回数据包含敏感信息时,我们可以在一个访问量高的站点或者自己博客插入一段js,去跨域加载这个jsonp接口,如果访问者之前登陆过(有cookie信息),则可以批量获取重要信息:

例如 我们在我们博客中加上这段内容

1
2
3
4
5
6
<script>
function evil(v){
alert(v);
}
</script>
<script src="http://aim.com/?callback=evil"></script>

aim.com这个jsonp接口返回的信息又包含敏感信息:

1
evil('username:test passwd:dfsjk1s');

当有用户访问我们博客且之前在aim.com登陆过时,则可以批量劫持敏感信息。

这类攻击常见的防御方式是判断reference是否为可信来源或添加随机值,但存在reference伪造(qq.com.evil.com)、空reference、暴力穷举等问题,最有效的方式还是综合防御(判断reference和添加随机字串),或使用加在url中的token可以完美解决。

callback函数可定义的安全问题

根据上面的内容,我们可以看到,callback函数的名称可以自定义,而输出环境又是js环境,如果没有严格过滤或审查,可以引起很多其他的攻击方式。

比如后台使用$callback = $_GET['callback'];print $callback.'(data)';这样子,认为callback是可信的,而攻击者完全可以将alert(/xss/)作为callback参数传递进去。

这种问题有两种解决方案:

#严格定义 Content-Type: application / json

这样的防御机制导致了浏览器不解析恶意插入的 XSS 代码

#过滤 callback 以及 JSON 数据输出

这样的防御机制是比较传统的攻防思维,对输出点进行 xss 过滤。

基础函数调用

如果我们的回调函数被硬编码进响应(即多个不同类型的请求都采用同样的回调函数名,例如callback等),那么就会存在基础函数调用的危害。

JSONP 漏洞挖掘

可以去搜索callback.json关键字

.json-callback

利用搜索引擎

1
2
inurl:.json
inurl:callback=

防御

  • 调用JSON文件限制Refererence 、部署一次性 Token在url中(QQ这么做的·http://r.qzone.qq.com/cgi-bin/tfriend/friend_show_qqfriends.cgi?uin=[QQ号码]&g_tk=[随机token])
  • 严格暗账 JSON 格式标准输出Content-Type及编码( Content-Type : application/json; charset=utf-8) 阻值了返回当成js执行的可能
  • 严格过滤callback函数名及JSON里数据的输出 按照xss过滤
  • 严格限制对 JSONP 输出callback函数名的长度,函数调用名不可预测