通過一篇文章由淺入深的理解JSONP并拓展
簡單描述
JSONP 是 JSON with padding(填充式 JSON 或參數(shù)式 JSON)的簡寫。
JSONP實現(xiàn)跨域請求的原理簡單的說,就是動態(tài)創(chuàng)建<script>
標簽,然后利用<script>
的src 不受同源策略約束來跨域獲取數(shù)據(jù)。
JSONP 由兩部分組成:回調函數(shù)和數(shù)據(jù)。回調函數(shù)是當響應到來時應該在頁面中調用的函數(shù)。回調函數(shù)的名字一般是在請求中指定的。而數(shù)據(jù)就是傳入回調函數(shù)中的 JSON 數(shù)據(jù)。
動態(tài)創(chuàng)建<script>
標簽,設置其src,回調函數(shù)在src中設置:
var script = document.createElement("script"); script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse"; document.body.insertBefore(script, document.body.firstChild);
在頁面中,返回的JSON作為response參數(shù)傳入回調函數(shù)中,我們通過回調函數(shù)來來操作數(shù)據(jù)。
function handleResponse(response){ // 對response數(shù)據(jù)進行操作代碼 }
上面是簡單直接的對JSONP 的描述,可能有些人不是很懂,我們下面一步一步分析
層層深入
先通過一個簡單的實例簡單的理解一下同源策略的作用
首先我們在本地寫入
1.html
<!DOCTYPE html> <html> <head> <title>GoJSONP</title> </head> <body> <script type="text/javascript"> function jsonhandle(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-3.3.1.min.js"> </script> <script type="text/javascript"> $(document).ready(function(){ $.ajax({ type : "get", url : "http://check.k0rz3n.com/test.php?id=1", dataType: "jsonp",//指定我們的請求是一個 jsonp 的請求 success : function(data) {//success 指定的是默認的回調函數(shù) jsonhandle(data); } }); }); </script> </body> </html>
我服務器上的test.php會返回json 格式的數(shù)據(jù)給客戶端
test1.php
<?php header('Content-Type:application/json; charset=utf-8'); $data = array('age'=>19,'name'=>'jianshu'); exit(json_encode($data)); ?>
如果正常訪問的話,那么我們的瀏覽器應該會彈出對話框,結果我們會得到這樣的結果
此處輸入圖片的描述
可以看到,瀏覽器發(fā)現(xiàn)這是一個跨域的請求,但是他在服務器的返回頭中缺沒有發(fā)現(xiàn)
Access-Control-Allow-Origin 值允許 http://localhost 的訪問,于是就攔截了。
也就是說,雖然瀏覽器受到了同源策略的限制,不允許實現(xiàn)跨域訪問,但是由于在開發(fā)過程中前后端的交互過程中不可避免地會涉及到跨域的請求(設計同源策略的人想必也發(fā)現(xiàn)了這個問題),于是設計者給我們留了一個后門,就是只要服務器響應頭中返回允許這個源的選項,那么跨域請求就會成功。(這里糾正一個誤區(qū),不要認為瀏覽器默認支持同源策略就意味著不同源的請求就不能發(fā)出去,其實還是能發(fā)出去的,只是要看響應頭而已。)
我們知道在頁面中有幾個東西是對同源策略免疫的,那就是 <img> 的src 、<link> 的 href 還有就是<script>的 src , JSONP 就是利用 script 標簽的sec 屬性實現(xiàn)跨區(qū)域請求的
script標簽的請求不論是不是同源一律不受同源策略的限制,那我們就找到了解決跨域訪問的方法(似乎這個方法一開始就存在…..)
我們改變一下代碼,本地直接通過script標簽請求服務器上的js,js 的內容就是調用參數(shù)已經(jīng)傳進去的本地的js函數(shù)
2.html
<!DOCTYPE html> <html> <head> <title>GoJSONP</title> </head> <body> <script type="text/javascript"> function jsonhandle(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-3.3.1.min.js"> </script> <script type="text/javascript" src="http://check.k0rz3n.com/remote.js"></script> </body> </html>
remote.js
jsonhandle({ "age" : 15, "name": "John", })
注意:
(1)遠程的js 代碼不需要script標簽
(2)這其實也給了我們一些啟示,就是我們使用 callback 函數(shù)請求的頁面實際上類型是javascript 的類型,我們可以在這里看一下瀏覽器會將哪些類型當做 javascript 解析:https://mathiasbynens.be/demo/javascript-mime-type
下圖可以看到我們成功利用<script>實現(xiàn)了跨域的訪問。
此處輸入圖片的描述
那JSONP和這個有啥關系,感覺已經(jīng)實現(xiàn)跨域了還沒有提到一點JSONP,上面說JSONP是基于script標簽的,個人感覺JSONP的優(yōu)勢就是能夠實現(xiàn)呢比較方便的函數(shù)選擇,傳一個參數(shù)就行了,不用像直接調用那樣必須要換js文件。
真相浮現(xiàn)
先用下面的代碼模擬jsonp的調用過程方便大家更好的理解jsonp的運行過程
3.html
<!DOCTYPE html> <html> <head> <title>GoJSONP</title> </head> <body> <script type="text/javascript"> function jsonhandle(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-3.3.1.min.js"> </script> <script type="text/javascript"> $(document).ready(function(){ var url = "http://check.k0rz3n.com/test1.php?id=1&callback=jsonhandle"; var obj = $('<script><\/script>'); obj.attr("src",url); $("body").append(obj); }); </script> </body> </html>
test1.php
<?php $data = array( 'age' => 20, 'name' => 'dada', ); $callback = $_GET['callback']; echo $callback."(".json_encode($data).")"; return;
我們在scipt標簽里面給出的鏈接是我遠程服務器的一個php的代碼,我給這個文件傳遞了一個參數(shù),作為我要調用的函數(shù)。服務器接收到這個參數(shù)以后把它當做函數(shù)名,并給這個函數(shù)傳遞了一個json的值作為用戶調用的函數(shù)的參數(shù),最終實現(xiàn)調用
下面是調用成功的截圖
實際上,jquery 給我們提供了現(xiàn)成的接口,我們可以不用這么麻煩
4.html
<!DOCTYPE html> <html> <head> <title>GoJSONP</title> </head> <body> <script type="text/javascript" src="jquery-3.3.1.min.js"></script> <script type="text/javascript"> function jsonhandle(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript"> $(document).ready(function(){ $.ajax({ type : "get", url : "http://check.k0rz3n.com/test1.php?id=1", dataType: "jsonp", jsonp:"theFunction", //指定回調函數(shù)在 URL 中的參數(shù)名(不指定默認為 callback) jsonpCallback: "jsonhandle",//指定回調函數(shù)名稱(如果不指定,服務器會隨機分配一個jQueryxxx 的名字) success : function(data) { console.info("調用success"); } }); }); </script> </body> </html>
這時候的請求的 URL 就像下面這個樣子:
http://check.k0rz3n.com/test1.php?id=1&theFunction=jsonhandle
服務器端頁面為:
test2.php
<?php $data = array( 'age' => 20, 'name' => 'dada', ); $callback = $_GET['theFunction']; echo $callback."(".json_encode($data).")"; return;
怎么樣,大概理解了吧,其實可以用一個非常形象的例子說明:
幼稚園吃午飯,小明吧貼有自己名字的碗(回調函數(shù))給了幼稚園阿姨(服務器),阿姨給小明盛好飯(json參數(shù))以后又把碗還給了小明。
就是這樣的一個過程。
相關拓展:JSONP攻擊
1.JSONP 跨域劫持
實際上就是由于服務器端對JSONP 的請求來源的檢查不嚴格導致的
攻擊者模擬用戶向有漏洞的服務器發(fā)送JSONP請求,然后就獲取到了用戶的某些信息,再將這些信息發(fā)送到攻擊者可控的服務器
2.JSONP 跨域劫持token 實現(xiàn)CSRF
通過 jsonp 發(fā)起請求,得到泄露的 csrf_token 然后,利用這個token 實現(xiàn)CSRF 攻擊
3.Referer 頭的繞過
在攻擊過程中可能會涉及到 referer 頭的繞過
- data:URL
為了逃避他的檢測我們可以選擇不發(fā)送referer這個頭,那么怎么做呢?這就涉及到 data:URL 頭
為了構造一個不帶HTTP Referer的請求,我們可以濫用data URI方案。因為我們正在處理的代碼包含了引號,雙引號,以及其他一些被阻止的語句,接著使用base64編碼我們的payload(回調函數(shù)定義以及腳本包含)
data:text/plain;base64our_base64_encoded_code:
以下3個HTML標簽允許我們使用data URI方案:
iframe (在src屬性中) – Internet Explorer下不工作 embed (在src屬性中) – Internet Explorer及Microsoft Edge下不工作 object (在data屬性中) – Internet Explorer及Microsoft Edge下不工作
2.從HTTPS向HTTP發(fā)起請求
如果目標網(wǎng)站可以通過HTTP訪問,也可以通過將我們的代碼托管在一個HTTPS頁面來避免發(fā)送HTTP Referer。如果我們從HTTPS頁面發(fā)起一個HTTP請求,瀏覽器為了防止信息泄漏是不會發(fā)送Referer header。以上我們要將惡意代碼托管在一個啟用了HTTPS的站點。
注意:由于mixed-content安全機制,在瀏覽器默認設置下是不會工作的。需要受害者手動允許瀏覽器發(fā)出的安全警告。
參考鏈接
- https://blog.csdn.net/u011897301/article/details/52679486
- https://blog.csdn.net/u014607184/article/details/52027879
- http://www.91ri.org/13407.html
- http://www.freebuf.com/articles/web/70025.html
- http://www.freebuf.com/articles/web/126347.html
- https://www.cnblogs.com/chiangchou/p/jsonp.html
總結
到此這篇關于JSONP拓展的文章就介紹到這了,更多相關理解JSONP并拓展內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
asp.net下利用js實現(xiàn)返回上一頁的實現(xiàn)方法小集
其實要實現(xiàn)這個功能主要還是要用到javascript2009-11-11ZeroClipboard插件實現(xiàn)多瀏覽器復制功能(支持firefox、chrome、ie6)
Zero Clipboard 利用透明的Flash讓其漂浮在復制按鈕之上,這樣其實點擊的不是按鈕而是Flash ,這樣將需要的內容傳入Flash,再通過Flash的復制功能把傳入的內容復制到剪貼板2014-08-08