JS跨域問(wèn)題

JS跨域問(wèn)題

  • 協(xié)議不同
    如http, https惕耕;
  • 端口不同
  • 主域相同,子域不同
  • 主域不同
  • ip地址和域名
    瀏覽器不會(huì)自動(dòng)做ip域名的映射

造成跨域的兩種策略

瀏覽器的同源策略會(huì)導(dǎo)致跨域,這里同源策略又分為以下兩種

DOM同源策略

禁止對(duì)不同源頁(yè)面DOM進(jìn)行操作班眯。這里主要場(chǎng)景是iframe跨域的情況,不同域名的iframe是限制互相訪問(wèn)的。

XmlHttpRequest同源策略

禁止使用XHR對(duì)象向不同源的服務(wù)器地址發(fā)起HTTP請(qǐng)求蓖柔。只要協(xié)議、域名风纠、端口有任何一個(gè)不同况鸣,都被當(dāng)作是不同的域,之間的請(qǐng)求就是跨域操作竹观。

為什么要有跨域限制

了解完跨域之后镐捧,想必大家都會(huì)有這么一個(gè)思考,為什么要有跨域的限制臭增,瀏覽器這么做是出于何種原因呢懂酱。其實(shí)仔細(xì)想一想就會(huì)明白,跨域限制主要是為了安全考慮誊抛。
AJAX同源策略主要用來(lái)防止CSRF攻擊列牺。如果沒(méi)有AJAX同源策略,相當(dāng)危險(xiǎn)拗窃,我們發(fā)起的每一次HTTP請(qǐng)求都會(huì)帶上請(qǐng)求地址對(duì)應(yīng)的cookie瞎领,那么可以做如下攻擊:用戶登錄了自己的銀行頁(yè)面 http://mybank.com泌辫,http://mybank.com向用戶的cookie中添加用戶標(biāo)識(shí)。用戶瀏覽了惡意頁(yè)面 http://evil.com九默。執(zhí)行了頁(yè)面中的惡意AJAX請(qǐng)求代碼震放。http://evil.comhttp://mybank.com發(fā)起AJAX HTTP請(qǐng)求,請(qǐng)求會(huì)默認(rèn)把http://mybank.com對(duì)應(yīng)cookie也同時(shí)發(fā)送過(guò)去驼修。銀行頁(yè)面從發(fā)送的cookie中提取用戶標(biāo)識(shí)殿遂,驗(yàn)證用戶無(wú)誤,response中返回請(qǐng)求數(shù)據(jù)乙各。此時(shí)數(shù)據(jù)就泄露了墨礁。而且由于Ajax在后臺(tái)執(zhí)行,用戶無(wú)法感知這一過(guò)程觅丰。
DOM同源策略也一樣饵溅,如果iframe之間可以跨域訪問(wèn),可以這樣攻擊:做一個(gè)假網(wǎng)站妇萄,里面用iframe嵌套一個(gè)銀行網(wǎng)站 http://mybank.com蜕企。把iframe寬高啥的調(diào)整到頁(yè)面全部,這樣用戶進(jìn)來(lái)除了域名冠句,別的部分和銀行的網(wǎng)站沒(méi)有任何差別轻掩。這時(shí)如果用戶輸入賬號(hào)密碼,我們的主網(wǎng)站可以跨域訪問(wèn)到http://mybank.com的dom節(jié)點(diǎn)懦底,就可以拿到用戶的輸入了唇牧,那么就完成了一次攻擊。

跨域的解決方式

解決方案

document.domain
window.name
jsonp
postMessage
cors

document.domain

  • 關(guān)鍵點(diǎn)
    跨域分為兩種聚唐,一種xhr不能訪問(wèn)不同源的文檔丐重,另一種是不同window之間不能進(jìn)行交互操作;
    document.domain主要是解決第二種情況,且只能適用于主域相同子域不同的情況杆查;
    document.domain的設(shè)置是有限制的扮惦,我們只能把document.domain設(shè)置成自身或更高一級(jí)的父域,且主域必須相同亲桦。例如:a.b.example.com中某個(gè)文檔的document.domain可以設(shè)成a.b.example.com崖蜜、b.example.com 、example.com中的任意一個(gè)客峭,但是不可以設(shè)成c.a.b.example.com豫领,因?yàn)檫@是當(dāng)前域的子域,也不可以設(shè)成baidu.com舔琅,因?yàn)橹饔蛞呀?jīng)不相同了等恐。
  • 兼容性:所有瀏覽器都支持;
  • 優(yōu)點(diǎn)
    可以實(shí)現(xiàn)不同window之間的相互訪問(wèn)和操作;
  • 缺點(diǎn)
    只適用于父子window之間的通信鼠锈,不能用于xhr闪檬;
    只能在主域相同且子域不同的情況下使用星著;
  • 使用方式
    a(當(dāng)前頁(yè)面或父頁(yè)面)頁(yè)面中加入document.domain = ‘example.com’;
    b(當(dāng)前頁(yè)面或子頁(yè)面)頁(yè)面中加入document.domain = ‘example.com’;
    a頁(yè)面訪問(wèn)b頁(yè)面里面的數(shù)據(jù)或者方法购笆;
  • Example
    有一個(gè)頁(yè)面,它的地址是http://www.example.com/a.html 虚循, 在這個(gè)頁(yè)面里面有一個(gè)iframe同欠,它的src是http://example.com/b.html
    1.在頁(yè)面 http://www.example.com/a.html 中設(shè)置document.domain:
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
<script type="text/javascript">
    document.domain = 'example.com';//設(shè)置成主域
    function test(){
        alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 對(duì)象
    }
</script>

2.在頁(yè)面 http://example.com/b.html 中也設(shè)置document.domain:

<script type="text/javascript">
    document.domain = 'example.com';//在iframe載入這個(gè)頁(yè)面也設(shè)置document.domain,使之與主頁(yè)面的document.domain相同
</script>

window.name

  • 關(guān)鍵點(diǎn)

  • window.name在頁(yè)面的生命周期里共享一個(gè)window.name;

  • 兼容性

  • 所有瀏覽器都支持横缔;

  • 優(yōu)點(diǎn)
    最簡(jiǎn)單的利用了瀏覽器的特性來(lái)做到不同域之間的數(shù)據(jù)傳遞铺遂;
    不需要前端和后端的特殊配制;

  • 缺點(diǎn)
    大小限制:window.name最大size是2M左右茎刚,不同瀏覽器中會(huì)有不同約定襟锐;
    安全性:當(dāng)前頁(yè)面所有window都可以修改,很不安全膛锭;
    數(shù)據(jù)類型:傳遞數(shù)據(jù)只能限于字符串粮坞,如果是對(duì)象或者其他會(huì)自動(dòng)被轉(zhuǎn)化為字符串,如下初狰;
    window.name非字符串測(cè)試
    使用方式:修改window.name的值即可莫杈;

  • Example
    a.html中代碼:

<script>
    window.name = '我是頁(yè)面a中設(shè)置的值';
    setInterval(function(){
        window.location = 'b.html';
    },2000)//兩秒后把一個(gè)新頁(yè)面b.html載入到當(dāng)前的window中
</script>

b.html中的代碼

<script>
    console.log(window.name);//讀取window.name的值
</script>

jsonp

  • 關(guān)鍵點(diǎn)
    瀏覽器對(duì)XHR做了同源策略,但并沒(méi)有將這種方式延續(xù)到script上(其實(shí)還有iframe奢入,img等)
    從而可以利用動(dòng)態(tài)script標(biāo)簽技術(shù)來(lái)做到跨域請(qǐng)求的作用筝闹。至于為什么會(huì)這樣設(shè)計(jì),本人也不太清楚腥光,有可能是歷史遺跡(漏洞)关顷,有可能是某些方面的技術(shù)瓶頸,也有可能是為了滿足某些需求專門(mén)定制的武福,總之這項(xiàng)技術(shù)方案我們過(guò)去可以用议双,現(xiàn)在可以用就ok,至于將來(lái)應(yīng)該也是會(huì)存在的艘儒,畢竟現(xiàn)在已經(jīng)應(yīng)用在很多家站點(diǎn)上聋伦,就算會(huì)廢棄,也會(huì)有一段時(shí)間迭代界睁。
    在js中觉增,我們直接用XMLHttpRequest請(qǐng)求不同域上的數(shù)據(jù)時(shí),是不可以的翻斟。但是逾礁,在頁(yè)面上引入不同域上的js腳本文件卻是可以的,jsonp正是利用這個(gè)特性來(lái)實(shí)現(xiàn)的。

  • 兼容性
    所有瀏覽器都兼容這種方式嘹履;

  • 優(yōu)點(diǎn)
    很明顯前端可以很輕松的做到跨域請(qǐng)求腻扇;

  • 缺點(diǎn)
    只能通過(guò)GET方式請(qǐng)求,一方面是參數(shù)長(zhǎng)度有限制砾嫉,二是安全性比較差幼苛;
    后端需要知道前端的cb是什么樣的結(jié)構(gòu),主要在參數(shù)和回調(diào)名焕刮;
    后端需要進(jìn)行參數(shù)和cb的拼接然后才能執(zhí)行舶沿;

<script type="text/javascript">
    function dosomething(jsondata){
        //處理獲得的json數(shù)據(jù)
    }
</script>
<script src="http://example.com/data.php?callback=dosomething"></script>

js文件載入成功后會(huì)執(zhí)行我們?cè)趗rl參數(shù)中指定的函數(shù)拟赊,并且會(huì)把我們需要的json數(shù)據(jù)作為參數(shù)傳入勋拟。所以jsonp是需要服務(wù)器端的頁(yè)面進(jìn)行相應(yīng)的配合的。

<?php
$callback = $_GET['callback'];//得到回調(diào)函數(shù)名
$data = array('a','b','c');//要返回的數(shù)據(jù)
echo $callback.'('.json_encode($data).')';//輸出
?>

最終提揍,輸出結(jié)果為:dosomething(['a','b','c']);

postMessage

  • 關(guān)鍵點(diǎn)
    window.postMessage(message,targetOrigin) 方法是html5新引進(jìn)的特性溉旋,可以使用它來(lái)向其它的window對(duì)象發(fā)送消息畸冲,無(wú)論這個(gè)window對(duì)象是屬于同源或不同源,目前IE8+观腊、FireFox邑闲、Chrome、Opera等瀏覽器都已經(jīng)支持window.postMessage方法恕沫。

  • 兼容性
    移動(dòng)端可以放心用监憎,但是pc端需要做降級(jí)處理,具體可以根據(jù)文中介紹的這幾種跨域方式來(lái)則情選擇婶溯;

  • 優(yōu)點(diǎn)
    不需要后端介入就可以非常簡(jiǎn)單的的做到跨域鲸阔,一個(gè)函數(shù)外加兩個(gè)參數(shù)(請(qǐng)求url,發(fā)送數(shù)據(jù))就可以搞定迄委;
    移動(dòng)端兼容性好褐筛;

  • 缺點(diǎn)
    無(wú)法做到一對(duì)一的傳遞方式:監(jiān)聽(tīng)中需要做很多消息的識(shí)別,由于postMessage發(fā)出的消息對(duì)于同一個(gè)頁(yè)面的不同功能相當(dāng)于一個(gè)廣播的過(guò)程叙身,該頁(yè)面的所有onmessage都會(huì)收到渔扎,所以需要做消息的判斷;
    安全性問(wèn)題:三方可以通過(guò)截獲信轿,注入html或者腳本的形式監(jiān)聽(tīng)到消息晃痴,從而能夠做到篡改的效果,所以在postMessage和onmessage中一定要做好這方面的限制财忽;
    發(fā)送的數(shù)據(jù)會(huì)通過(guò)結(jié)構(gòu)化克隆算法進(jìn)行序列化倘核,所以只有滿足該算法要求的參數(shù)才能夠被解析,否則會(huì)報(bào)錯(cuò)即彪,如function就不能當(dāng)作參數(shù)進(jìn)行傳遞紧唱;

  • 例子
    otherWindow.postMessage(message, targetOrigin);
    otherWindow: 對(duì)接收信息頁(yè)面的window的引用。可以是頁(yè)面中iframe的contentWindow屬性漏益;window.open的返回值蛹锰;通過(guò)name或下標(biāo)從window.frames取到的值。
    message: 所要發(fā)送的數(shù)據(jù)绰疤,string類型铜犬。
    targetOrigin: 用于限制otherWindow,“*”表示不作限制

  • Example
    a.com/index.html中的代碼:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
    var ifr = document.getElementById('ifr');
    // 若寫(xiě)成'http://b.com/c/proxy.html'效果一樣
    // 若寫(xiě)成'http://c.com'就不會(huì)執(zhí)行postMessage了
    var targetOrigin = 'http://b.com';  
    ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

b.com/index.html中的代碼:

<script type="text/javascript">
    window.addEventListener('message', function(event){
        // 通過(guò)origin屬性判斷消息來(lái)源地址
        if (event.origin == 'http://a.com') {
            alert(event.data);    // 彈出"I was there!"
            alert(event.source);  // 對(duì)a.com峦睡、index.html中window對(duì)象的引用
                                  // 但由于同源策略翎苫,這里event.source不可以訪問(wèn)window對(duì)象
        }
    }, false);
</script>

cors(Cross-origin resource sharing)

  • 關(guān)鍵點(diǎn)
  • cors是一種通過(guò)前后端http header配置來(lái)進(jìn)行跨域的一種方式;
    兼容性:如果不考慮pc端的IE榨了,移動(dòng)端的opera的話那兼容性還是不錯(cuò)的,針對(duì)ie和opera可以做適當(dāng)?shù)慕导?jí)處理攘蔽;
    poseMessage兼容性
    安全策略
    請(qǐng)求
    origin:通過(guò)http頭中的origin判斷域名是否是允許的龙屉;
    Example-Same-origin:如果http origin不存在,最好能夠自己在請(qǐng)求頭中加入該參數(shù)來(lái)標(biāo)示是否是同源满俗,true表示請(qǐng)求來(lái)自于同域名下(同域名下請(qǐng)求不帶origin)转捕;如果該字段存在并且為true則允許請(qǐng)求接口,否則禁止唆垃;
    Example_source_origin:該參數(shù)同origin五芝,是在origin不存在的情況下用來(lái)標(biāo)示請(qǐng)求來(lái)源的url;
    返回
    Access-Control-Allow-Origin: origin辕万,origin表示允許哪些網(wǎng)站請(qǐng)求枢步,不建議設(shè)置為*;
    Access-Control-Expose-Headers:Example-Access-Control-Allow-Source-Origin渐尿,允許http返回中包含該字段醉途,可以通過(guò)這種方式在返回頭中加入自定義字段,如該例子中的Example-Access-Control-Allow-Source-Origin;
  • 優(yōu)點(diǎn)
    前端方便不少砖茸,只需要發(fā)請(qǐng)求而不用考慮跨域問(wèn)題隘擎;
    安全性能夠得以控制和保障;
  • 缺點(diǎn)
    兼容性不全面凉夯,需要做降級(jí)處理货葬;
  • Example
    對(duì)于客戶端,我們還是正常使用xhr對(duì)象發(fā)送ajax請(qǐng)求劲够。唯一需要注意的是震桶,我們需要設(shè)置我們的xhr屬性withCredentials為true,不然的話再沧,cookie是帶不過(guò)去的哦尼夺,設(shè)置: xhr.withCredentials = true;對(duì)于服務(wù)器端,需要在 response header中設(shè)置如下兩個(gè)字段:
    Access-Control-Allow-Origin: http://www.yourhost.com
    Access-Control-Allow-Credentials:true
    這樣,我們就可以跨域請(qǐng)求接口了淤堵。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末寝衫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拐邪,更是在濱河造成了極大的恐慌慰毅,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扎阶,死亡現(xiàn)場(chǎng)離奇詭異汹胃,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)东臀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)着饥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人惰赋,你說(shuō)我怎么就攤上這事宰掉。” “怎么了赁濒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵轨奄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拒炎,道長(zhǎng)挪拟,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任击你,我火速辦了婚禮玉组,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘果漾。我一直安慰自己球切,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布绒障。 她就那樣靜靜地躺著吨凑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪户辱。 梳的紋絲不亂的頭發(fā)上鸵钝,一...
    開(kāi)封第一講書(shū)人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音庐镐,去河邊找鬼恩商。 笑死,一個(gè)胖子當(dāng)著我的面吹牛必逆,可吹牛的內(nèi)容都是我干的怠堪。 我是一名探鬼主播揽乱,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼粟矿!你這毒婦竟也來(lái)了凰棉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤陌粹,失蹤者是張志新(化名)和其女友劉穎撒犀,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體掏秩,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡或舞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蒙幻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片映凳。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖杆煞,靈堂內(nèi)的尸體忽然破棺而出魏宽,到底是詐尸還是另有隱情,我是刑警寧澤决乎,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站派桩,受9級(jí)特大地震影響构诚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铆惑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一范嘱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧员魏,春花似錦丑蛤、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至虏束,卻和暖如春棉饶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背镇匀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工照藻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人汗侵。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓幸缕,卻偏偏與公主長(zhǎng)得像群发,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子发乔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349