解決 jsonP 安全問題


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'});"

?>
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM