摘要:同源策略及跨域訪問同源策略同源策略約束了兩個域之間資源的加載方式,是一個很重要的安全機制用來隔離那些有潛在安全隱患的文檔。
同源策略及跨域訪問 同源策略
同源策略(Same-origin policy)約束了兩個域之間資源的加載方式,是一個很重要的安全機制用來隔離那些有潛在安全隱患的文檔。
何為源(orgin)一個源由一個URL的協議(protocol)、主機(host)和端口(port)進行定義。如果兩個頁面擁有相同的協議、主機和端口一致的話,我們就可以稱它們為同源。下面的表格比較了不同的URL跟http://store.company.com/dir/page.html這個URL的同源情況:
URL | 是否同源 | 理由 |
---|---|---|
http://store.company.com/dir2... | 是 | |
http://store.company.com/dir/... | 是 | |
https://store.company.com/sec... | 否 | 協議不同 |
http://store.company.com:81/d... | 否 | 端口不同 |
http://news.company.com/dir/o... | 否 | 主機不同 |
同源策略控制了兩個源之間的交互,例如你使用XMLHttpRequest發起一個請求,或者使用元素加載一張圖片,就會產生兩個源之間的交互。而當兩個源不相同時,有些交互會被允許,而有些則不被允許。而不允許的情況,就是我們常說的跨域訪問問題。那什么情況下不同源的交互會被允許,什么情況下又不被允許呢?大致可以分為如下的情況:
鏈接、跳轉和表單提交這些在跨域的情況下都是被允許的。例如調用支付寶接口進行支付就是典型的跨域表單提交的場景,這種跨域的調用是被允許的。但是這個很容易被利用來進行CSRF攻擊,所以我們的表單提交需要做好這方面的防護。
跨域的資源內嵌是被允許的。下面是一些資源內容的例子:
使用加載Javascript。只有同源的腳本在語法錯誤時會顯示錯誤信息。
使用加載CSS。跨源的CSS文件要求使用正確的Content-Type 響應頭。
使用加載圖片。
使用和加載媒體文件。
使用 、和加載插件。
使用 @font-face加載字體。有些瀏覽器允許加載跨域的字體,有些則不允許。
使用 和加載任何東西。
跨域文檔間使用Javascript腳本進行交互,API的訪問有限制。例如使用ifame嵌入的頁面或者使用window.open打開的頁面,如果跟父頁面不同源,則想通過Javascript去操作父頁面的DOM,是不允許的(反過來亦然)。
舉個例子,假設有這么一個頁面http://www.example.com/index.html:
.....
然后在http://sub.example.com/iframe.html頁面對父頁面的背景色進行修改:
......
由于兩個頁面不同源,所以子頁面對父頁面的操作被禁止,例如在Firefox上你會看到以下的報錯:
Error: Permission denied to access property "document"
不同源之間的XMLHttpRequest調用(也就是我們常說ajax調用)是不被允許的,這個也是我們最常遇到的跨域訪問場景。例如我們在http://example.com/index.html頁面進行如下的ajax調用:
var xhr = new XMLHttpRequest(); var url = "http://otherexample.com/api/get-data"; xhr.open("GET", url, true); xhr.onreadystatechange = handler; xhr.send();
在Firefox下會報如下錯誤:
已攔截跨源請求:同源策略禁止讀取位于 http://otherexample.com/api/get-data 的遠程資源。(原因:CORS 頭缺少 "Access-Control-Allow-Origin")。跨域訪問的解決方案
一個頁面的源是可以修改的,修改的方法很簡單,就是通過Javascript腳本設置document.domain的值。舉個例子,我們在頁面http://store.company.com/dir/other.html執行下面的代碼:
document.domain = "company.com";
那么這個頁面的域將會由store.company.com變成company.com,后面在判斷是否同源的時候,主機將會使用company.com這個值,而不是store.company.com。
那是不是修改域后就能跟同域的頁面進行交互呢。答案是否定的。例如,如果你在頁面中通過iframe嵌入http://company.com/dir/page.html這個頁面,然后通過javascript去跟這個頁面交互,你會發現瀏覽器會報錯,就跟我們之前那個例子一樣。按照上面的源的定義,這時候兩個頁面應該是同源的,為什么呢?因為修改document.domain會導致端口號被設為null。所以另外一個頁面也需要把document.domain修改為相同的值,這樣兩個頁面的主機和端口就一致了,可以進行互相的訪問了。
既然源可以修改,那么是不是就解決了我們的跨域問題呢?明顯沒這么簡單。首先,這種方法是有很大限制條件的,document.domain這個值只能修改為這個頁面的當前域或者當前域的超級域。所以,這個方法只能解決同一超級域下的頁面跨域問題。其次,它的使用場景也很有限,因為它需要頁面執行Javascript腳本,所以也就是說一般只能應用于頁面跟頁面的交互,例如訪問ifame頁面或者window.open打開的頁面等等。所以如果你想用來解決ajax之類的跨域調用,這個方法就無能為力了。
使用代理也是解決跨域訪問的一個方法。上面修改document.domain的方法只能用來訪問子域名的頁面,無法訪問不同域的頁面,而使用代理則沒有這個問題。
例如我們有一個頁面http://example.com/,需要訪問http://otherexample.com/這個頁面,我們不直接對這個頁面進行訪問,而是通過請求另外一個同源的頁面,這個頁面在后端通過代理服務器把請求轉發到http://otherexample.com/,獲取數據并返回給客戶端。
另外,這個方法同樣可以用于解決ajax的跨域訪問問題。
JSONP也被經常用來解決ajax的跨域調用問題。JSONP請求并不是通過XMLHttpRequest發起,而是使用進行調用。前面說過,內嵌資源一般不受同源政策影響,所以可以加載其他源的資源。
舉個例子,假設http://www.example.com/頁面,想異步調用http://www.otherexample.com/ajax.json這個接口,這個接口會返回如下的數據:
{ "id": "123", "name": "Captain Jack Sparrow" }
如果我們通過XMLHttpRequest發起調用,就會因為同源政策而失敗。所以我們通過進行調用,并通過參數傳遞我們的回調函數名:
然后接口獲取到callback函數名后,把原來返回的數據作為函數的參數,最終返回如下的Javascript:
myFunction({"id": "123", "name": "Captain Jack Sparrow"});
然后myFunction就會執行,達到了調用的目的。
這個方法在大多數情況下都很有用,但是它也有它的局限。一是它需要后端的配合,因為后端的接口需要根據約定的參數獲取回調函數名,然后跟返回數據進行拼接,最后進行響應。二是它只能進行異步的調用,因為它的原理是通過動態生成加載JS的方法,而這個過程是異步的,所以如果你想進行同步的調用,那么這個方法就無能為力了。
Web Messaging(又稱cross-document messaging)是HTML5的一個接口,允許兩個不同源的文檔之間進行通信。
它主要用到了接口里的postMessage方法,這個方法可以把純文本消息從一個域發送到另外一個域。消息可以發送以下的對象:
發送方文檔里frame和iframe。
發送方通過Javascript打開的頁面。
發送方的父頁面。
打開發送方頁面的頁面。
消息event包含了以下的屬性:
data:收到的消息。
origin:發送方的源,包括協議、主機名和端口。
source:發送方的window對象。
舉個例子,假設example.net下的文檔A跟文檔里用iframe加載的example.com下的文檔B進行通信,我們向文檔B發送消息Hello B,Javascript代碼大致如下:
var o = document.getElementsByTagName("iframe")[0]; o.contentWindow.postMessage("Hello B", "http://example.com/");
我們先獲取到文檔B的contentWindow對象,然后把需要發送到消息以及文檔B的源傳給postMessage。文檔B則通過監聽message事件,捕獲到事件,并作相應的處理:
function receiver(event) { if (event.origin == "http://example.net") { if (event.data == "Hello B") { event.source.postMessage("Hello A, how are you?", event.origin); } else { alert(event.data); } } } window.addEventListener("message", receiver, false);
需要注意的是,postMessage是個非阻塞的調用,也就是說是異步的。
Web Messaging主要用于跨域文檔間的通訊,所以它不能用來解決所有跨域調用的問題,例如ajax調用。而且IE瀏覽器對它的支持也很有限。
CORS(Cross-Origin Resource Sharing)是W3C提出的一個用于服務器端控制數據跨域傳輸的一個機制。 它的原理是通過一些新增加的HTTP頭讓服務端能定義哪些源的請求可以被允許。
簡單舉個例子,假設我們在頁面http://example.com/發起一個跨域的XMLHttpRequest請求:
var xhr = new XMLHttpRequest(); var url = "http://otherexample.com/api/get-data/"; xhr.open("GET", url, true); xhr.onreadystatechange = handler; xhr.send();
正常情況這個請求是不允許的。但是如果我們在服務端返回以下響應頭:
Access-Control-Allow-Origin: *
這個Access-Control-Allow-Origin頭表示服務端允許哪些源的請求,*表示允許所有的源,所以上面的請求就被允許了。當然正常情況下我們不會這樣做,我們需要把Access-Control-Allow-Origin設置為真正想允許的源。在請求頭會有一個叫Origin的頭,它的值就是請求方的源(例如上面的請求會有Origin: http://example.com這個請求頭),服務端應該根據這個頭去返回相應的Access-Control-Allow-Origin頭。
當然CORS的實際使用會比上面的例子復雜得多,具體可以參考MDN的這篇文章和W3C的規范。
CORS可以說是解決XMLHttpRequest跨域調用的一個比較好的方法,但IE瀏覽器對它的支持同樣很有限,直到IE11才完全支持,所以在移動端更能發揮它的作用。
參考https://developer.mozilla.org...
https://developer.mozilla.org...
https://www.sitepoint.com/wor...
https://en.wikipedia.org/wiki...
http://caniuse.com/#search=po...
http://caniuse.com/#search=cors
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/11219.html
摘要:三哪些會受到同源策略限制對于瀏覽器來說,除了會受到同源策略的限制外,瀏覽器加載的一些第三方插件也有各自的同源策略。九的現代瀏覽器允許腳本直連一個地址而不管同源策略。 一、Origin(源) 源由下面三個部分組成: 域名 端口 協議 兩個 URL ,只有這三個都相同的情況下,才可以稱為同源。 下來就以 http://www.example.com/page.html 這個鏈接來比較說...
摘要:扯了這么多,自然不是為了吹水,而是要為了引出前端開發的一個重要的知識點同源策略什么是同源策略出于保護用戶信息安全的目的,現在的瀏覽器都會實施同源策略這個政策,所謂同源策略指的是不同源的客戶端腳本在沒有明確授權情況下,不允許讀寫對方的資源。 導語你家的小孩帶了他的朋友來你們的家里玩,你家的小孩如果要在自家屋里拿玩具玩、拿東西吃你自然是不會阻止,但是如果你家小孩的朋友人品不行,亂拿東西吃、...
摘要:扯了這么多,自然不是為了吹水,而是要為了引出前端開發的一個重要的知識點同源策略什么是同源策略出于保護用戶信息安全的目的,現在的瀏覽器都會實施同源策略這個政策,所謂同源策略指的是不同源的客戶端腳本在沒有明確授權情況下,不允許讀寫對方的資源。 導語你家的小孩帶了他的朋友來你們的家里玩,你家的小孩如果要在自家屋里拿玩具玩、拿東西吃你自然是不會阻止,但是如果你家小孩的朋友人品不行,亂拿東西吃、...
摘要:同源策略是什么同源策略是瀏覽器的一個安全功能,不同源的數據禁止訪問。或許你可以說驗證,在瀏覽器沒有同源策略的情況下這些都可以繞過去。總結同源策略是蠻好的,防御了大部分的攻擊。 前端最基礎的就是 HTML+CSS+Javascript。掌握了這三門技術就算入門,但也僅僅是入門,現在前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS),本著提升技術水平,打牢基礎知識的中心思...
摘要:上節我們講了同源策略,這節我們講講如何跨域。當這些從的腳本執行出錯,因為違背了同源策略為了保證用戶信息不被泄露,錯誤信息不會顯示出來,取而代之只會返回一個。 前端最基礎的就是 HTML+CSS+Javascript。掌握了這三門技術就算入門,但也僅僅是入門,現在前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS),本著提升技術水平,打牢基礎知識的中心思想,我們開課啦(每...
閱讀 1698·2021-11-12 10:36
閱讀 1615·2021-11-12 10:36
閱讀 3441·2021-11-02 14:46
閱讀 3798·2019-08-30 15:56
閱讀 3531·2019-08-30 15:55
閱讀 1462·2019-08-30 15:44
閱讀 1043·2019-08-30 14:00
閱讀 2735·2019-08-29 18:41