专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
芋道源码  ·  Nginx 实现动态封禁IP,详细教程来了 ·  2 天前  
芋道源码  ·  一款高颜值的在线项目任务管理神器 ·  2 天前  
macrozheng  ·  Java找工作太逆天了。。 ·  4 天前  
芋道源码  ·  Mybatis ... ·  4 天前  
芋道源码  ·  再见,Navicat 太炸了! ·  4 天前  
51好读  ›  专栏  ›  ImportNew

扯谈 web 安全之 JSON

ImportNew  · 公众号  · Java  · 2017-01-28 22:40

正文

(点击上方公众号,可快速关注)


来源:hengyunabc,

blog.csdn.net/hengyunabc/article/details/26305203

如有好文章投稿,请点击 → 这里了解详情


前言


JSON(JavaScript Object Notation),可以说是事实的浏览器,服务器交换数据的标准了。目测其它的格式如XML,或者其它自定义的格式会越来越少。


为什么JSON这么流行?


和JavaScript无缝对接是一个原因。还有一个重要原因是可以比较轻松的实现跨域。如果是XML,或者其它专有格式,则很难实现跨域,要通过flash之类来实现。任何一种数据格式,如何解析处理不当,都会存在安全漏洞。下面扯谈下JSON相关的一些安全东东。


在介绍之前,先来提几个问题:


  • 为什么XMLHttpRequest要遵守同源策略?


  • XMLHttpRequest 请求会不会带cookie?



  • 服务器返回的数据是这样子的:


    jQuery1102045087050669826567_1386230674292({'name':'abc', 'age':18})


    浏览器会执行直接执行这个JS函数。


    所以,如果在callback函数的名字上做点手脚,可以执行任意的JS代码。所以说callback名字一定要严格过滤。当然,callback函数的名字通常是程序自己控制的,但是不能排除有其它被利用的可能。那么callback函数的名字,如何过滤?应当只允许合法的JS函数命名,用正则来匹配应该是这样子的:


    ^[0-9a-zA-Z_.]+$


    正则可能比较慢,可以写一个函数来判断:


    static boolean checkJSONPCallbackName(String name) {

        try {

            for (byte c : name.getBytes("US-ASCII")) {

                if ((c >= '0' && c = 'a' && c = 'A' && c

                {

                    continue;

                } else {

                    return false;

                }

            }

            return true;

        } catch (Throwable t) {

            return false;

        }

    }


    实际上对callback函数名字进行严格检验还有其它的一个好处,就是防范了很多UTF-7编码攻击。因为UTF-7编码的头部都是带有特殊字符的,如”+/v8″,”+/v9″,这样就过滤掉非法编码的请求了。 


    update: 2016-3-22 


    spring 4.1里有一个AbstractJsonpResponseBodyAdvice ,里面是用正则匹配来判断是否合法的jsonp函数名。


    public abstract class AbstractJsonpResponseBodyAdvice extends AbstractMappingJacksonResponseBodyAdvice {

     

        /**

         * Pattern for validating jsonp callback parameter values.

         */

        private static final Pattern CALLBACK_PARAM_PATTERN = Pattern.compile("[0-9A-Za-z_\\.]*");


    jsonp的请求的验证


    jsonp在使用的时候,还有容易犯的错误是没有验证用户的身份。


    第一,操作是否是用户自己提交的,而不是别的网页用

    (调用结果数据)


    于是,就执行了XSS。


    另外用IFrame也是可以的。但是我在IE8上测试,url的后缀需要是html才会触发。


    IE把没有声明返回Content-Type的请求当做了”text/html”类型的,然后解析就有问题了。只要服务器端显式设置了Content-Type为”application/json”,则IE不会识别编码,就不会触发漏洞。所以说服务器端的Content-Type一定要设置对。尽管设置之后调试有点麻烦,但是却大大提高了安全性。 


    • JSON格式设置为:”application/json”


    • JavaScript设置为:”application/x-javascript”


    • JavaScript还有一些设置为:”text/javascript”等,都是不规范的。


    其它的一些东东


    MongoDB注入


    这个实际上就是JSON注入,简单的字符串拼接,可能会引发各种数据被修改的问题。


    JSON解析库的问题


    有些JSON库解析库支持循环引用,那么是否可以构造特别的数据,导致其解析失败?从而引起CPU使用过高,拒绝服务等问题?


    FastJSON的一个StackOverflowError Bug:https://github.com/alibaba/fastjson/issues/76


    有些JSON库解析有问题:http://www.freebuf.com/articles/web/10672.html


    JSON-P


    有人提出一个JSON-P的规范,但是貌似目前都没有浏览器有支持这个的。原理是对于JSONP请求,浏览器可以要求服务器返回的MIME是”application/json-p”,这样可以严格校验是否合法的JSON数据。


    CORS(Cross-Origin Resource Sharing)


    为了解决跨域调用的安全性问题,目前实际上可用的方案是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的了。


    最初的问题


    回到最初的问题:


    • 为什么XMLHttpRequest要遵守同源策略?


    即使XMLHttpRequest是不带Cookie的,也是有可能造成数据泄露的。比如内部网站是根据IP限制访问的,如果XMLHttpRequest不遵守同源策略,那么攻击者可以在用户浏览网页的时候,发起请求,取得内部网站数据。


    • XMLHttpRequest 请求会不会带cookie?


    同域情况下会,不同域情况下不会。如果服务器设置Access-Control-Allow-Credentials: true ,也是可以跨域带Cookie的。