Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 369|回复: 0

解决 jsonP 安全问题

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-5-7 14:57:36 | 显示全部楼层 |阅读模式

    jsonp安全性防范,分为以下几点:

    1、防止callback参数意外截断js代码,特殊字符单引号双引号,换行符均存在风险


    2、防止callback参数恶意添加标签(如script),造成XSS漏洞


    3、防止跨域请求滥用,阻止非法站点恶意调用

    针对第三点,我们可以通过来源refer白名单匹配,以及 cookieToken 机制来限制

     

    举例说明  京东白名单


    而前两点,传统的做法分为以下几种:


    1、纯手工过滤特殊字符,引号尖括号等,一旦发现潜在恶意字符则服务端拒绝,返回错误。

    此种方式较为严格,但是随之而来的问题是失败率会有所提升,尤其对于对外开发者。

    而且JS中恶意字符的变形十分,此方式需要枚举所有非法字符,可能存在疏漏。

     

     

     

    我们不应该将潜在的恶意字符都一概屏蔽,因为确实有些需求需要传入并存储这些字符。


    2、对于callback参数作严整的格式检查,或强制约定指定格式。基本可以彻底解决安全问题,

    但同样是对调用端不是完全透明,使用者需要额外去知晓相关限制和约定,可能会造成不必要的沟通成本。

     

     


    3、返回包体添加header头部,强制指定MIME类型,避免按HTML方式解析,防止XSS漏洞。

    这似乎是个很完美的解决方案。

    但是十分诡异的是,在某些版本的火狐浏览器下,直接访问MIME类型为JAVASCRIPT的请求时,浏览器仍然会按照HTML解析。

     

    或许是该浏览器设计的缺陷,但它忽略了我们设置的header。无法保证所有浏览器严格按照MIME类型解析。

    我们的关注点一直在于如何限制用户输入,但是请从另外一个层面去考虑该问题,或许就会豁然开朗。

     

    我们先了解一下JS本身的特性。


    JSONP的本质是构造全局回调函数,之后加载script标签触发回调函数。
    通常我们使用函数可以这么写

    function test(){}test();

    而在全局的函数也就默认是window的成员。也可以显示书写为

    window.test = function(){};window.test();

    而JS中对象的成员是可以使用字符串索引的方式访问的,故进一步改造为

    window['test']=function(){};window['test']();

     

     

    现在有注意到么,如此一来我们已经把函数名已经完全限制在了字符串上下文,

    理论上只要做好了防注入工作,callback参数是不可能跳出字符串上下文意外执行代码的。

    PHP为例,单字符串防止注入甚至可以直接使用json_encode该字符串实现。

     

     

    window['alert("123");abc']();

     

    上面的callback参数虽然有注入的风险,可以由于callback参数严格限制在字符串内部,仅会作为文本,不会意外执行

    但仍然存在xss漏洞问题
    看下面例子

    window['<script>alert(123);</script>']();

    我们虽然已经保证了<script>严格限制在引号内部,不会造成js注入,但是直接在浏览器中输入该jsonp请求仍会按照HTML解析,产生XSS

    漏洞,即便设置了header也很难防范。

     

     

    在进一步,我们只需要保证浏览器内不会明文出现<>标签,那么问题便可彻底解决。


    基本思路是在服务端做一次urlencode。而在output输出decodeURIComponent(‘#####’)来规避显示尖括号。

    Urlencode过的字符串,只可能包含字母数字%,也顺便解决了注入的问题

     

    最终附上一段简短的代码。根本解决jsonp的安全问题

     

    <?php header('Content-type: text/javascript'); //加上此句可以消除chrome的警告 

    $callback = urlencode($_GET['callback']);

    echo "window[decodeURIComponent('{$callback}')]({ret:0,msg:’OK’});"

     

    请求1:http://www.test.com/a.php?callback=alert(123);abc

    响应1:window[decodeURIComponent('alert(123)%3Babc')]({ret:0,msg:'OK'});

     

    请求2:http://www.test.com/a.php?callback=<script>alert(123);</script>

    响应2:window[decodeURIComponent('%3Cscript%3Ealert(123)%3B%3C%2Fscript%3E')]({ret:0,msg:'OK'});

     

    上述几个例子都可以证明jsonp安全漏洞已被彻底规避,即便存在尝试注入的恶意参数,仍能最大限度保证程序完全正常工作触发回调。

     

     

    附上源码

     

    <html>
    <head>
        <title>GoJSONP</title>
    </head>
    <body>
    <script type="text/javascript">
        function jsonhandle(data){
            console.table(data);
        }
    </script>
    <script type="text/javascript" src="http://code.jquery.com/jquery-3.3.1.js">
    </script>
    <script type="text/javascript">
        $(document).ready(function(){
            // var url = "http://www.project.com/project/l.php?callback=alert('123');jsonhandle";
            var url = "http://www.project.com/project/l.php?callback=jsonhandle";
            var obj = $('<script><\/script>');
            obj.attr("src",url);
            $("body").append(obj);
        });
    </script>
    </body>
    </html>
    <?php 
    
     header('Content-type: text/javascript'); //加上此句可以消除chrome的警告 
    
    //xss
    
    // $callback = $_GET['callback'];
    // echo "$callback({ret:0,msg:'ok'});"
    
    //safe
    $callback = urlencode($_GET['callback']); 
    echo "window[decodeURIComponent('{$callback}')]({ret:0,msg:'OK'});"
    
    ?>
     

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-19 06:46 , Processed in 0.066611 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表