瀏覽器同源策略和跨域方法

什么是同源策略

同源策略 (Same-Origin Policy) 最早由 Netscape 公司提出, 所謂同源就是要求, 域名, 協(xié)議, 端口相同。非同源的腳本不能訪問或者操作其他域的頁面對(duì)象(如DOM等)。作為著名的安全策略, 雖然它只是一個(gè)規(guī)范, 并不強(qiáng)制要求, 但現(xiàn)在所有支持 javaScript 的瀏覽器都會(huì)使用這個(gè)策略。 以至于該策略成為瀏覽器最核心最基本的安全功能, 如果缺少了同源策略, web的安全將無從談起。

同源策略要求三同, 即: 同域, 同協(xié)議, 同端口。

同域即host相同, 頂級(jí)域名, 一級(jí)域名, 二級(jí)域名, 三級(jí)域名等必須相同, 且域名不能與 ip 對(duì)應(yīng);
同協(xié)議要求, http與https協(xié)議必須保持一致;
同端口要求, 端口號(hào)必須相同。

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

只要協(xié)議、域名、端口有任何一個(gè)不同,都被當(dāng)作是不同的域,跨域就是訪問非本域的資源。

跨域?qū)崿F(xiàn)方式
1、JSONP
2、CORS
3、降域
4、PostMessage

JSONP 的原理是什么

JSONP是服務(wù)器與客戶端跨源通信的常用方法。最大特點(diǎn)就是簡單適用,老式瀏覽器全部支持,服務(wù)器改造非常小。它的基本思想是,AJAX 無法跨域是受到“同源政策”的限制,但是帶有src屬性的標(biāo)簽(例如<script>、<img>、<iframe>)是不受該政策限制的,因此通過向頁面中動(dòng)態(tài)添加標(biāo)簽來完成對(duì)跨域資源的訪問,這也是 JSONP 方案最核心的原理。

通常我們使用都是引用的靜態(tài)資源(主要是 js 文件),其實(shí)它也可以用來引用動(dòng)態(tài)資源(php、jsp、aspx等),后臺(tái)服務(wù)被訪問后返回一個(gè)“JavaScript函數(shù)調(diào)用”形式的字符串,由于是字符串,因此在后臺(tái)的時(shí)候不會(huì)起到任何作用,但到了前臺(tái),放入標(biāo)簽之內(nèi),就成了一個(gè)合法的 JavaScript 函數(shù)調(diào)用,實(shí)參是我們真正需要的數(shù)據(jù),被調(diào)用的回調(diào)函數(shù)也已經(jīng)實(shí)現(xiàn)了,因此就會(huì)順利的被調(diào)用。

JSONP 最大的優(yōu)點(diǎn)就是兼容性非常好,其原理決定了即便在非常古老的瀏覽器上也能夠很好的被實(shí)現(xiàn)。

JSONP 的主要缺點(diǎn)有兩個(gè),一是只能 GET 不能 POST,因?yàn)槭峭ㄟ^引用的資源,參數(shù)全都顯式的放在URL里,和 AJAX 沒有關(guān)系。二是存在安全隱患,動(dòng)態(tài)插入標(biāo)簽其實(shí)就是一種腳本注入,會(huì)受到跨站腳本攻擊。

CORS是什么

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

瀏覽器將CORS請(qǐng)求分成兩類:簡單請(qǐng)求(simple request)和非簡單請(qǐng)求(not-so-simple request)。

簡單請(qǐng)求:瀏覽器直接發(fā)出CORS請(qǐng)求。具體來說,就是在頭信息之中,增加一個(gè)Origin字段。

非簡單請(qǐng)求:是對(duì)服務(wù)器有特殊要求的請(qǐng)求,比如請(qǐng)求方法是PUTDELETE,或者Content-Type字段的類型是application/json。

跨域的解決方式

JSONP

JSONP是服務(wù)器與客戶端跨源通信的常用方法。利用script標(biāo)簽可以引入其它域的JS這一特性,來實(shí)現(xiàn)跨域訪問接口。JSONP最大特點(diǎn)就是簡單適用,老式瀏覽器全部支持,服務(wù)器改造非常小。但前提是后端支持。

1、動(dòng)態(tài)添加<script>元素,向服務(wù)器發(fā)出請(qǐng)求

var change = document.querySelector('.change')
var newsList = document.querySelector('.news-list')

change.addEventListener('click', function(){
   var script = document.createElement('script');
   script.src= 'http://localhost:8080/getNews?callback=appendHtml'
   document.head.appendChild(script);
   document.head.removeChild(script);
})

2、用src 中 callback參數(shù) 指定回調(diào)函數(shù)的名字

function appendHtml(news){
  var html = '';
  for( var i=0; i<news.length; i++){
  html += '<li>' + news[i] + '</li>';
  }
  newsList.innerHTML = html;
  }
})

3、服務(wù)器收到這個(gè)請(qǐng)求以后,會(huì)將數(shù)據(jù)會(huì)放在回調(diào)函數(shù)的參數(shù)位置返回。

app.get('/getNews', function(req, res){
    var news = [
        "第11日前瞻:中國沖擊4金 博爾特再戰(zhàn)200米羽球",
        "正直播柴飚/洪煒出戰(zhàn) 男雙力爭會(huì)師決賽",
        "女排將死磕巴西!郎平安排男陪練模仿對(duì)方核心",
        "沒有中國選手和巨星的110米欄 我們還看嗎?",
        "中英上演奧運(yùn)金牌大戰(zhàn)",
        "博彩賠率挺中國奪回第二紐約時(shí)報(bào):中國因?qū)κ址幎鴣G失的獎(jiǎng)牌最多",
        "最“出柜”奧運(yùn)?同性之愛閃耀里約",
        "下跪拜謝與洪荒之力一樣 都是真情流露"
    ]
    var data = [];
    for(var i=0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index]);
        news.splice(index, 1);
    }
    var callback = req.query.callback;
    if(callback){
        res.send(callback + '('+ JSON.stringify(data) + ')');
    }else{
        res.send(data);
    }
})

JSONP的優(yōu)點(diǎn)是:它不像XMLHttpRequest對(duì)象實(shí)現(xiàn)的Ajax請(qǐng)求那樣受到同源策略的限制;它的兼容性更好,在更加古老的瀏覽器中都可以運(yùn)行,不需要XMLHttpRequest或ActiveX的支持;并且在請(qǐng)求完畢后可以通過調(diào)用callback的方式回傳結(jié)果。

JSONP的缺點(diǎn)則是:它只支持GET請(qǐng)求而不支持POST等其它類型的HTTP請(qǐng)求;它只支持跨域HTTP請(qǐng)求這種情況,不能解決不同域的兩個(gè)頁面之間如何進(jìn)行JavaScript調(diào)用的問題。

CORS

CORS(Cross-Origin Resource Sharing)跨域資源共享,定義了必須在訪問跨域資源時(shí),瀏覽器與服務(wù)器應(yīng)該如何溝通。CORS背后的基本思想就是使用自定義的HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通,從而決定請(qǐng)求或響應(yīng)是應(yīng)該成功還是失敗。在服務(wù)器中設(shè)置響應(yīng)頭字段即可:

res.header("Access-Control-Allow-Origin","url")

CORS與JSONP的使用目的相同,但是比JSONP更強(qiáng)大。

JSONP只支持GET請(qǐng)求,CORS支持所有類型的HTTP請(qǐng)求。JSONP的優(yōu)勢在于支持老式瀏覽器,以及可以向不支持CORS的網(wǎng)站請(qǐng)求數(shù)據(jù)。

postMessage

postMessage() 方法允許來自不同源的腳本采用異步方式進(jìn)行有限的通信,可以實(shí)現(xiàn)跨文本檔、多窗口、跨域消息傳遞。第二個(gè)參數(shù)可以是*但如果你設(shè)置了一個(gè)URL但不相符,那么該事件不會(huì)被分發(fā)。

父頁面發(fā)送消息:

window.frames[0].postMessage('message', origin)

iframe接受消息:

window.addEventListener('message',function(e){
    if(e.source!=window.parent) return;//若消息源不是父頁面則退出
      //TODO ...
});

其中 e 對(duì)象有三個(gè)重要的屬性

  • data, 表示父頁面?zhèn)鬟f過來的message
  • source, 表示發(fā)送消息的窗口對(duì)象
  • origin, 表示發(fā)送消息窗口的源(協(xié)議+主機(jī)+端口號(hào))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容