任務(wù)31-同源策略妒貌、跨域、jsonp

問答

1. 什么是同源策略

同源是指域名铸豁、協(xié)議灌曙、端口相同。
同源策略(Same-Origin Policy)是瀏覽器的一個(gè)功能节芥;
最初在刺,它的含義是指,A網(wǎng)頁(yè)設(shè)置的 Cookie头镊,B網(wǎng)頁(yè)不能打開蚣驼,從而保證用戶信息的安全性。隨著互聯(lián)網(wǎng)的發(fā)展相艇,"同源政策"越來越嚴(yán)格颖杏。目前,如果非同源坛芽,共有三種行為受到限制:
(1) Cookie留储、LocalStorage 和 IndexDB 無法讀取。
(2) DOM 無法獲得咙轩。
(3) AJAX 請(qǐng)求不能發(fā)送获讳。
換句話說:不同源的客戶端腳本在沒明確授權(quán)的情況下,不能讀寫對(duì)方的資源活喊。

2. 什么是跨域丐膝?跨域有幾種實(shí)現(xiàn)形式

簡(jiǎn)單地理解就是因?yàn)镴avaScript同源策略的限制,a.com 域名下的js無法操作b.com或是c.a.com域名下的對(duì)象钾菊。更詳細(xì)的說明可以看下表:


實(shí)現(xiàn)形式:?
1. document.domain+iframe
應(yīng)用范圍:這種辦法只能解決主域相同而子域不同帅矗,且是iframe形式的跨域;
存在問題:安全性结缚,當(dāng)一個(gè)站點(diǎn)(b.a.com)被攻擊后损晤,另一個(gè)站點(diǎn)(c.a.com)會(huì)引起安全漏洞。
2.JSONP
應(yīng)用范圍:因?yàn)槭腔趕cript標(biāo)簽红竭,所有只能進(jìn)行GET請(qǐng)求
存在問題:存在安全性問題尤勋,可被注入可執(zhí)行的js代碼(callback=alert(1)
), 對(duì)于這個(gè)問題,只能通過外界的字符串過濾來解決茵宪,如禁止callback中傳入括號(hào)最冰,使用正則去除左右括號(hào),callback = callback.replace( /\(/g,"" )
稀火,callback = callback.replace( /\)/g,"" )

3.CORS
給被訪問方設(shè)置Access-Control-Allow-Origin暖哨,如在php文件頭部寫入header('Access-Control-Allow-Origin:http://a.com'),表示允許來自源http://a.com的請(qǐng)求。這是跨域AJAX請(qǐng)求的根本解決方法凰狞。
相比JSONP只能發(fā)GET請(qǐng)求篇裁,CORS允許任何類型的請(qǐng)求沛慢。但是IE10及以下IE版本不支持。
4.HTML5 postMessage
這是HTML5的新功能达布,用postMessage支持基于web的實(shí)時(shí)消息傳遞团甲。
5.利用iframe和location.hash
這個(gè)方法比較繞,原理是利用location.hash來傳值黍聂。url中#號(hào)及其后面的內(nèi)容就是location.hash,改變hash的值頁(yè)面并不會(huì)刷新躺苦,所以可以利用hash值來進(jìn)行數(shù)據(jù)傳遞。這種方法缺點(diǎn)也很多产还,諸如數(shù)據(jù)直接暴露在了url中匹厘,數(shù)據(jù)容量和類型都有限等。
6.利用window.name
主要利用window.name值不隨url改變而改變脐区,只要當(dāng)前頁(yè)面沒被關(guān)閉愈诚,window.name的值就不會(huì)改變。

3. jsonp 的原理是什么

ajax請(qǐng)求受同源策略影響坡椒,不允許進(jìn)行跨域請(qǐng)求扰路,而script標(biāo)簽src屬性中的鏈接卻可以訪問跨域的js腳本尤溜,利用這個(gè)特性倔叼,服務(wù)端不再返回JSON格式的數(shù)據(jù),而是返回一段調(diào)用某個(gè)函數(shù)的js代碼宫莱,在src中進(jìn)行了調(diào)用丈攒,這樣實(shí)現(xiàn)了跨域。

4. CORS是什么

CORS是一個(gè)W3C標(biāo)準(zhǔn)授霸,全稱是"跨域資源共享"(Cross-origin resource sharing)巡验。它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請(qǐng)求碘耳,從而克服了AJAX只能同源使用的限制显设。
CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前辛辨,所有瀏覽器都支持該功能捕捂,IE瀏覽器不能低于IE10。

整個(gè)CORS通信過程斗搞,都是瀏覽器自動(dòng)完成指攒,不需要用戶參與。對(duì)于開發(fā)者來說僻焚,CORS通信與同源的AJAX通信沒有差別允悦,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源虑啤,就會(huì)自動(dòng)添加一些附加的頭信息隙弛,有時(shí)還會(huì)多出一次附加的請(qǐng)求架馋,但用戶不會(huì)有感覺。

因此全闷,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器绩蜻。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信室埋。

練習(xí)

1. 本地搭建服務(wù)器办绝,演示同源策略

1. 本地搭建服務(wù)器(如果使用 SAE 可創(chuàng)建不同的代碼版本,這樣可通過1.xxx.sinapp.com和2.xxx.sinapp.com 訪問了)
2. 修改 本地host姚淆,通過不同域名訪問本地服務(wù)器孕蝉。比如訪問http://a.com/index.html, http://b.com/ajax.php,本質(zhì)是
3. 在 index.html 里使用 ajax 接口訪問 http://b.com/ajax.php 里的數(shù)據(jù)腌逢。
4. 查看輸出報(bào)錯(cuò)

這里以XAMPP為例演示降淮,具體步驟:

  1. 在XAMPP軟件的htdocs/tests/cross-origin目錄下新建兩個(gè)文件,index.html和main.js搏讶。其中佳鳖,index.html的主要內(nèi)容如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>同源策略</title>
</head>
<body>
    <script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js"></script>

    <!-- 測(cè)試一:a.com/index引用b.com域名下的main.js文件 -->
    <script src="http://b.com/tests/cross-origin/main.js"></script>

    <!-- 測(cè)試二:a.com/index通過ajax請(qǐng)求b.com域名下的main.js文件 -->
    <script type="text/javascript">
        $.get('//b.com/tests/cross-origin/main.js',function(response){
                console.log(response);
        })
    </script>

    <!-- 測(cè)試三:a.com/index 通過ajax請(qǐng)求a.com域名下的main.js文件 -->
    <script type="text/javascript">
        $.get('//a.com/tests/cross-origin/main.js',function(response){
            console.log(response);
        })
    </script>
</body>
</html>

main.js的內(nèi)容如下:

alert (1);
  1. 以管理員權(quán)限運(yùn)行記事本,用記事本打開路徑Windows/System32/drivers/etc下的hosts文件媒惕,添加如下兩條IP和域名的對(duì)應(yīng)信息系吩。目的是讓a.com和b.com兩個(gè)域名都指向本地機(jī)。
127.0.0.1 a.com
127.0.0.1 b.com
  1. 啟動(dòng)XAMPP妒蔚,瀏覽器地址欄輸入a.com/tests/cross-origin/index.html
  2. 測(cè)試結(jié)果:
  • 測(cè)試一結(jié)果:頁(yè)面 alert(1)穿挨,無報(bào)錯(cuò)。說明a.com可以引用b.com里的main.js文件(只是引用肴盏,并未讀寫)科盛。

  • 測(cè)試二結(jié)果:頁(yè)面無彈框,控制臺(tái)報(bào)錯(cuò)菜皂。受同源策略的限制贞绵,a.com不能讀寫b.com域名下文件,因而控制臺(tái)會(huì)報(bào)錯(cuò)恍飘,同時(shí)main.js里的腳本也不會(huì)執(zhí)行


  • 測(cè)試三結(jié)果:頁(yè)面alert(1),控制臺(tái)打印“alert(1)”
    a.com/index通過ajax請(qǐng)求了a.com域名下的main.js文件榨崩,說明相同域名之下,文件是可以互相讀寫的常侣。


2. 至少使用一種方式解決跨域問題

  • 方法一:document.domain+iframe
    對(duì)于主域相同而子域不同的例子蜡饵,可以通過設(shè)置document.domain的辦法來解決。如a.comchild1.a.com,可以在這兩個(gè)文件中分別加上document.domain = 'a.com'胳施,然后通過a.html文件中創(chuàng)建一個(gè)iframe溯祸,去控制iframe的contentDocument。示例:host文件添加127.0.0.1 child1.a.com,新建index1文件焦辅,內(nèi)容如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index1</title>
</head>
<body>
    <h1>hello world</h1>
    <iframe src="http://child1.a.com/tests/cross-origin/index2.html" frameborder="0" style="background-color: #ccc"></iframe>
    <script type="text/javascript">
         window.onload = function(){
            document.domain = 'a.com';
            var iframe = window.frames[0];
            console.log(iframe.window.name);
         }
    </script>
</body>
</html>

index2文件內(nèi)容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index2</title>
</head>
<body background="#ccc">
    <p>index2</p>
    <script type="text/javascript">
        document.domain = "a.com";
      window.name = "index2"
    </script>
    
</body>
</html>

瀏覽器地址欄輸入a.com/tests/cross-origin/index1.html博杖,可以看到,控制臺(tái)打印出了“index2”, 即筷登,通過document.domain方法剃根,a.com讀取到了指向child1.a.com的iframe窗口的window.name屬性的值。

  • 方法二:JSONP
    雖然瀏覽器默認(rèn)禁止了跨域訪問前方,但并不禁止在頁(yè)面中引用其他域的JS文件狈醉,并可以自由執(zhí)行引入的JS文件中的function(包括操作cookie、Dom等等)惠险。根據(jù)這一點(diǎn)苗傅,可以方便地通過創(chuàng)建script節(jié)點(diǎn)的方法來實(shí)現(xiàn)完全跨域的通信。以下演示a.com域名下的JSONP.html引用b.com域名下的server.php文件
    JSONP.html文件內(nèi)容如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JSONP</title>
</head>
<body>
    <script type="text/javascript">
        window.foo = function(data){
            alert(data);
        }
    </script>
    <!-- 動(dòng)態(tài)引用 -->
    <script type="text/javascript">
        var script = document.createElement('script');
        script.src = '//b.com/tests/cross-origin/server.php?callback=foo';
        document.body.appendChild(script);
    </script>
    <!-- 靜態(tài)引用班巩,和動(dòng)態(tài)引用無本質(zhì)差別 -->
    <!-- <script type="text/javascript" src="http://b.com/tests/cross-origin/server.php?callback=foo"></script> -->
</body>
</html>

server.php文件內(nèi)容如下:

<?php
  $callback = $_GET["callback"];
  echo $callback . '("來自b.com里的數(shù)據(jù)")';   //foo("來自b.com里的數(shù)據(jù)")
?>

瀏覽器地址欄輸入//a.com/tests/cross-origin/JSONP.html,可以看到如下圖彈框渣慕,說明通過jsonp已經(jīng)成功得到了b.com下的數(shù)據(jù)。


  • 方法三:CORS
    以下演示a.com下的CORS.html通過ajax請(qǐng)求b.com域名下的server-CORS.php文件
    CORS.html文件內(nèi)容如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CORS</title>
</head>
<body>
    <script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js"></script>
    <script type="text/javascript">
        $.get("http://b.com/tests/cross-origin/server-CORS.php?callback=小美",function(response){
                console.log(response);  //小美:22
        })
    </script>
</body>
</html>

server-CORS.php文件內(nèi)容如下:

<?php
         //設(shè)置php頭部信息抱慌,表示允許a.com訪問
        header('Access-Control-Allow-Origin:http://a.com');
        $arr = array('小明'=>'18','小紅'=>'20','小美'=>'22');
        $callback = $_GET["callback"];

        echo $callback.':'.$arr[$callback];
?>

瀏覽器地址欄輸入http://a.com/tests/cross-origin/CORS.html,可以看到控制臺(tái)打印出“小美:22”逊桦,說明通過給php設(shè)置Access-Control-Allow-Origin頭部信息可以實(shí)現(xiàn)跨域。

  • 方法四:使用HTML5 postMessage
    a.com下h5-index.html中的代碼:
<iframe id="ifr" src="http://b.com/tests/cross-origin/h5-index2.html" style="background-color: #ccc"></iframe>
    <script type="text/javascript">
        window.onload = function(){
            var ifr = document.getElementById('ifr');
            var targetOrigin = 'http://b.com';
            ifr.contentWindow.postMessage('我在這里',targetOrigin);

        }
    </script>

b.com下h5-index2.html中的代碼:

<script type="text/javascript">
        window.addEventListener('message',function(event){
                // 通過origin屬性判斷消息來源地址
                if(event.origin = 'http://a.com'){
                    alert(event.data);  // 彈出"我在這里"
                    alert(event.source);  // 對(duì)a.com抑进、index.html中window對(duì)象的引用强经。
                                          //但由于同源策略,這里event.source不可以訪問window對(duì)象
                }
        })
    </script>

最終效果:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末单匣,一起剝皮案震驚了整個(gè)濱河市夕凝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌户秤,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逮矛,死亡現(xiàn)場(chǎng)離奇詭異鸡号,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)须鼎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人摇邦,你說我怎么就攤上這事茫虽。” “怎么了赡译?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵仲吏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)裹唆,這世上最難降的妖魔是什么誓斥? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮许帐,結(jié)果婚禮上劳坑,老公的妹妹穿的比我還像新娘。我一直安慰自己成畦,他們只是感情好距芬,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著循帐,像睡著了一般蔑穴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惧浴,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天存和,我揣著相機(jī)與錄音,去河邊找鬼衷旅。 笑死捐腿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的柿顶。 我是一名探鬼主播茄袖,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼嘁锯!你這毒婦竟也來了宪祥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤家乘,失蹤者是張志新(化名)和其女友劉穎蝗羊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仁锯,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耀找,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了业崖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片野芒。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖双炕,靈堂內(nèi)的尸體忽然破棺而出狞悲,到底是詐尸還是另有隱情,我是刑警寧澤妇斤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布摇锋,位于F島的核電站丹拯,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏乱投。R本人自食惡果不足惜咽笼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望戚炫。 院中可真熱鬧剑刑,春花似錦、人聲如沸双肤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)茅糜。三九已至七芭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蔑赘,已是汗流浹背狸驳。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缩赛,地道東北人耙箍。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像酥馍,于是被迫代替她去往敵國(guó)和親辩昆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容