浏览器的同源策略与跨域
本文所有案例在本地址都可找到:https://github.com/dancingZhou/sameOrigin/tree/dev
什么是同源策略
兩個頁面地址中的協議、域名和端口號一致,則表示同源。
例如該地址 https://www.google.com 和以下地址對比
| http://www.google.com | 否 | 協議不一致 |
| https://google.com | 否 | 域名不一致 |
| https://www.google.com:81 | 否 | 端口號不一致 |
| https://www.google.com/a/s.html | 是 | 協議,域名和端口號都一致 |
同源策略的限制:
存儲在瀏覽器中的數據,如localStroage、Cooke和IndexedDB不能通過腳本跨域訪問
不能通過腳本操作不同域下的DOM
不能通過ajax請求不同域的數據
為什么要同源策略
設置同源限制主要是為了安全,如果沒有同源限制存在瀏覽器中的Cookie等其他數據可以任意讀取,不同域下DOM任意操作,Ajax任意請求的話如果瀏覽了惡意網站那么就會泄漏這些隱私數據。
Cookie一般用來保存登錄狀態。在登錄一個銀行網站后此時瀏覽器中就保存了登錄的狀態,同時瀏覽了惡意網站,這時Cookie的信息沒有同源限制的話惡意網站就可以獲取這些Cookie信息來達到不為人知的目的。
如果可以操作不同域下的DOM可以用如下方式完成盜取信息。在自己的網站上嵌入一個iframe地址設置成銀行地址,然后讓iframe全屏顯示,當你一不小心上當了輸入你賬號密碼,我就可以通過DOM操作獲取到輸入的信息。
Ajax的限制同Cookie,如果帶上Cookie去跨域訪問接口就可以通過程序的驗證被認為身份是合法的。
既然瞥見危害一角自然要嚴加防范,限制非同源操作。
怎么規避同源策略
在看法一個網站的過程中有的數據并不在同一臺服務器上這時怎么跨域調用就是一個很棘手的問題,可以通過以下幾個方式來規避同源的限制。
DOM同源策略的規避
hash
因為hash的改變并不會引起頁面的刷新同時可以通過 window.onhashchange事件監聽到hash的改變,所以可以通過hash來跨域傳遞數據。
<!-- http://example.com/index.html --> <html><head><meta charset="utf8"/><title>跨域DEMO --- hash</title></head><body><iframe id="iframe" src="http://example2.com/index.html"></iframe><script>var ifra = document.getElementById('iframe');ifra.onload = function(){// ifra 加載完成了ifra.src = ifra.src + '#data';}</script></body> </html> <!-- http://example2.com/index.html --> <!-- 在iframe中的頁面(example2.com)如果和iframe所在頁面(example.com)不同域是不能獲取所在頁面的DOM,然后通過hash將數據傳遞回去的,也就是說如果同域就可以通過該方法向所在頁面傳遞數據 --> <html><head><meta charset="utf8"/><title>跨域DEMO --- hash</title></head><body><script>window.onhashchange = function(){// 打印通過hash傳過來的數據console.log( location.hash ); }</script></body> </html>該方法會直接暴露所傳遞的數據并且對所傳數據有大小限制。
document.domain
若兩個文檔的域相同則可以獲取對方的DOM對象,并且可以通過設置 document.domain 的值來讓兩個文檔的域保持一致,但是 document.domain 并不是可以設置任何值,只能設置為當前域的超域,比如:
m.example.com 設置為 example.com,并且不能 example.com 設置為 m.example.com 也不能將 m.example.com 設置為 example2.com。
所以document.domain只可以在擁有相同的主域名的不同子域名之間跨域。
<!--http://a.example.com--> <html><head><meta charset="utf8"/><title>跨域DEMO --- document.domain</title></head><body><p id="data">我在 a.example.com 下</p><iframe id="ifra" src="http://b.example.com/index.html"></iframe><script>// 這里為什么也要設置呢?因為document.domain的賦值會導致端口被覆蓋成null,并且js中沒有手段單獨設置端口,所以這里設置一遍這樣就和iframe中的一致了。document.domain = 'example.com';var ifra = document.getElementById('ifra');ifra.onload = function(){console.log( ifra.contentWindow.document.getElementById('data').innerHTML ); // 我是b.example.com下的}</script></body> </html> <!--http://b.example.com--> <html><head><meta charset="utf8"/><title>跨域DEMO --- document.domain</title></head><body><p id="data">我是b.example.com下的</p><script>document.domain = 'example.com';console.log( parent.document.getElementById('data').innerHTML ); // 我在 a.example.com 下</script></body> </html>window.name
window.name有一個特性,即使當前窗口的地址改變了window.name的值也不會改變??梢岳眠@一特性來進行跨域,步驟如下:
window.postMessage
以上幾種跨域的方法都屬于破解行為,而postMessage是H5為跨域提供的解決方法。
otherWindow.postMessage(message, targetOrigin[, transfer]) <!--http://example.com--> <html><head><meta charset="utf8"/><title>跨域DEMO --- window.postMessage</title></head><body><iframe id="ifra" src="http://example3.com/index.html"/><script>var ifra = document.getElementById('ifra');ifra.onload = function(){ifra.contentWindow.postMessage('我來自example.com', 'http://example3.com')}</script></body> </html> <!--http://example3.com--> <html><head><meta charset="utf8"/><title>跨域DEMO --- window.postMessage</title></head><body><iframe src="http://example2.com/index.html"/><script>window.addEventListener('message', function(messageEvent){console.log( messageEvent.data ); // 我來自example.com}, false)</script></body> </html>messageEvent對象上的屬性中有三個屬性要注意,分別是:
Ajax同源策略的規避
jsonp
雖然跨域限制了Ajax請求,但是卻并不影響跨域引用腳本。
<script>function callback (data) {console.log(data); // 上面的加載完成之后就會打印出后臺傳過來的數據 "數據"} </script> <script src="http://example.com/index.php?arg=val1&jsonp=callback"></script> <?phpecho $_GET['jsonp'] . '(' . '數據' . ')'; ?>上面的 index.php 接口返回的是一段調用 函數的js代碼 callback(data),其中data就是接口要返回的數據。而這個callback是事先在頁面上寫好的處理數據的回調函數,并且回調函數的名稱通過URL參數的形式傳遞給了后端接口,這樣就完成了一次跨域。
注:jsonp只支持GET請求。
CORS
cors(跨域資源共享)
參考
總結
以上是生活随笔為你收集整理的浏览器的同源策略与跨域的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS中捉摸不透的==(宽松等于)
- 下一篇: 获取DOM元素方法小结