标签:json js javascript web 安全
JSON(JavaScript Object Notation),可以说是事实的浏览器,服务器交换数据的标准了。目测其它的格式如XML,或者其它自定义的格式会越来越少。
为什么JSON这么流行?
和JavaScript无缝对接是一个原因。
还有一个重要原因是可以比较轻松的实现跨域。如果是XML,或者其它专有格式,则很难实现跨域,要通过flash之类来实现。
任何一种数据格式,如何解析处理不当,都会存在安全漏洞。下面扯谈下JSON相关的一些安全东东。
在介绍之前,先来提几个问题:
String user = "test01"; String password = "12345', admin:'true"; String json = "{user:'%s', password:'%s'}"; System.out.println(String.format(json, user, password)); //{user:'test01', password:'12345', admin:'true'}
String string = "{user:'test01',password:'hello', password:'world'}"; JSONObject parse = JSON.parseObject(string); String password = parse.getString("password"); System.out.println(password); //world当JSON数据key重复了会怎么处理?大部分JSON解析库都是后面的参数覆盖了前面的。
下面的演示了修改别人密码的例子:
//user%3Dtest01%26password%3D12345%27%2Cuser%3Dtest02" //user=test01&password=12345',user=test02 HttpServletRequest request = null; String user = request.getParameter("user"); //检查test01是否登陆 String password = request.getParameter("password"); String content = "{user:'" + user + "', password:'" + password + "'}"; User user = JSON.parseObject(content, User.class); //{"password":"12345","user":"test02"} updateDb(user);
现在的浏览器都提供了原生的方法 JSON.parse(str) 来转换为JS对象。
如果是IE8之前的浏览器,要使用这个库来解析:https://github.com/douglascrockford/JSON-js
参考:http://zh.wikipedia.org/wiki/JSON#.E5.AE.89.E5.85.A8.E6.80.A7.E5.95.8F.E9.A1.8C
JQuery里内置了JSON解析库
var url = 'http://localhost:8080/testJsonp?callback=?'; $.getJSON(url, function(data){ alert(data) });jquery自动把?转成了一个带时间戳特别的函数(防止缓存):
http://localhost:8080/testJsonp?callback=jQuery1102045087050669826567_1386230674292&_=1386230674293相当于插入了这么一个<script>标签:
<script src="http://localhost:8080/testJsonp?callback=jQuery1102045087050669826567_1386230674292&_=1386230674293"></script>服务器返回的数据是这样子的:
jQuery1102045087050669826567_1386230674292({'name':'abc', 'age':18})浏览器会执行直接执行这个JS函数。
^[0-9a-zA-Z_.]+$正则可能比较慢,可以写一个函数来判断:
static boolean checkJSONPCallbackName(String name) { try { for (byte c : name.getBytes("US-ASCII")) { if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') { continue; } else { return false; } } return true; } catch (Throwable t) { return false; } }
因为UTF-7编码的头部都是带有特殊字符的,如"+/v8","+/v9",这样就过滤掉非法编码的请求了。
window.__defineSetter__('x', function() { alert('x is being assigned!'); }); window.x=1;会很神奇地弹出一个alert窗口,说明我们定义的setter函数起作用了。
[{'user':'test01','age':18},{'user':'test02,'age':19},{'user':'test03','age':20}]在攻击页面上插入以下的代码,就可以获取到用户的所有的朋友的信息。
<script> Object.prototype.__defineSetter__('user',function(obj) {alert(obj); } ); </script> <script src="http://www.test.com/friends"></script>这个漏洞在前几年很流行,比如qq邮箱的一个漏洞:http://www.wooyun.org/bugs/wooyun-2010-046
现在的浏览器都已经修复了,可以下载一个Firefox3.0版本来测试下。目前的浏览器在解析JSON Array字符串的时候,不再去触发setter函数了。但对于object.xxx 这样的设置,还是会触发。
有这样的一个jsonp调用接口:
http://jipiao.taobao.com/hotel/remote/livesearch.do?callback=%2B%2Fv8%20%2BADwAaAB0AG0APgA8AGIAbwBkAHkAPgA8AHMAYwByAGkAcAB0AD4AYQBsAGUAcgB0ACgAMQApADsAPAAvAHMAYwByAGkAcAB0AD4APAAvAGIAbwBkAHkAPgA8AC8AaAB0AG0APg
url decoder之后是:
http://jipiao.taobao.com/hotel/remote/livesearch.do?callback=+/v8 +ADwAaAB0AG0APgA8AGIAbwBkAHkAPgA8AHMAYwByAGkAcAB0AD4AYQBsAGUAcgB0ACgAMQApADsAPAAvAHMAYwByAGkAcAB0AD4APAAvAGIAbwBkAHkAPgA8AC8AaAB0AG0APg
因为jsonp调用是直接返回callback包装的数据,所以实际上,上面的请求直接返回的是:
+/v8 +ADwAaAB0AG0APgA8AGIAbwBkAHkAPgA8AHMAYwByAGkAcAB0AD4AYQBsAGUAcgB0ACgAMQApADsAPAAvAHMAYwByAGkAcAB0AD4APAAvAGIAbwBkAHkAPgA8AC8AaAB0AG0APg-(调用结果数据)
IE做了UTF-7解码之后数据是这样子的:
<htm><body><script>alert(1);</script></body></htm>(调用结果数据)
JSON格式设置为:"application/json"
JavaScript设置为:"application/x-javascript"
JavaScript还有一些设置为:"text/javascript"等,都是不规范的。
这个实际上就是JSON注入,简单的字符串拼接,可能会引发各种数据被修改的问题。
有些JSON库解析库支持循环引用,那么是否可以构造特别的数据,导致其解析失败?从而引起CPU使用过高,拒绝服务等问题?
FastJSON的一个StackOverflowError Bug:
https://github.com/alibaba/fastjson/issues/76
有些JSON库解析有问题:
http://www.freebuf.com/articles/web/10672.html
有人提出一个JSON-P的规范,但是貌似目前都没有浏览器有支持这个的。
原理是对于JSONP请求,浏览器可以要求服务器返回的MIME是"application/json-p",这样可以严格校验是否合法的JSON数据。
为了解决跨域调用的安全性问题,目前实际上可用的方案是CORS:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
http://www.w3.org/TR/cors/
原理是通过服务器端设置允许跨域调用,然后浏览器就允许XMLHttpRequest跨域调用了。
CORS可以发起GET/POST请求,不像JSONP,只能发起GET请求。
默认情况下,CORS请求是不带cookie的。
我个人认为,这个方案也很蛋疼,一是需要服务器配置,二是协议复杂。浏览器如果不能确定是否能够跨域调用,还要先进行一个Preflight Request。。
实际上,即使服务器不允许CORS,XMLHttpRequest请求实际上是发送出去,并且返回数据的了,只是浏览器没有让JS环境拿到而已。
另外,我认为有另外一种数据泄露的可能:黑客可能控制了某个路由,他不能随意抓包,但是他可以在回应头里插入一些特别的头部,比如:
Access-Control-Allow-Credentials: true那么,这时XMLHttpRequest请求就是带cookie的了。
回到最初的问题:
http://www.json.org/
http://www.slideshare.net/wurbanski/nosql-no-security
https://github.com/douglascrockford/JSON-js
http://toolswebtop.com/ 在线编码转换,可以转换UTF-7
http://www.thespanner.co.uk/2011/05/30/json-hijacking/
http://www.thespanner.co.uk/2009/11/23/bypassing-csp-for-fun-no-profit/
http://stackoverflow.com/questions/1830050/why-same-origin-policy-for-xmlhttprequest
标签:json js javascript web 安全
原文地址:http://blog.csdn.net/hengyunabc/article/details/26305203