摘要:同源策略瀏覽器出于安全方面的考慮,不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方的資源。傳回后回調(diào)函數(shù)立即執(zhí)行參數(shù)是后端產(chǎn)生的數(shù)據(jù)從而實現(xiàn)相應的功能。
同源策略
瀏覽器出于安全方面的考慮,不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方的資源。
同源指的是:
同協(xié)議
同域名
同端口
作用:保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)
例1:A網(wǎng)站是一家銀行,用戶登錄以后,又去瀏覽其他網(wǎng)站。如果其他網(wǎng)站可以讀取A網(wǎng)站的 Cookie,會發(fā)生什么?很顯然,如果 Cookie 包含隱私(比如存款總額),這些信息就會泄漏。除此之外,Cookie 往往用來保存用戶的登錄狀態(tài),如果用戶沒有退出登錄,其他網(wǎng)站就可以冒充用戶,為所欲為。(因為瀏覽器同時還規(guī)定,提交表單不受同源政策的限制)
例2:惡意網(wǎng)站的頁面通過iframe嵌入了銀行的登錄頁面(二者不同源),如果沒有同源限制,惡意網(wǎng)頁上的javascript腳本就可以在用戶登錄銀行的時候獲取用戶名和密碼,從而造成相關(guān)的風險。
對于當前頁面來說頁面中 JS 文件的域不重要,重要的是當前頁面所在的域與 腳本中涉及到的域(例如xht的open方法的url)是否同源
跨域跨域:瀏覽器出于安全方面的考慮設置了同源策略來限制不同域之間的交互,但是也阻礙了不域之間的協(xié)助。為了實現(xiàn)不同域之間的交互、協(xié)作,因此需要“跨域”。
跨域窗口通信 降域降域獲取同一 Cookie:Cookie 是服務器寫入瀏覽器的一小段信息,只有同源的網(wǎng)頁才能共享。但是,兩個網(wǎng)頁一級域名相同,只是二級域名不同,瀏覽器允許通過設置document.domain 共享 Cookie。
example:A 網(wǎng)頁是 http://w1.example.com/a.html,B 網(wǎng)頁是http://w2.example.com/b.html,那么只要設置相同的 document.domain,兩個網(wǎng)頁就可以共享 Cookie。
JavaScript
// A網(wǎng)頁和B網(wǎng)頁設置相同的 document.domain document.domain = "example.com"
// A網(wǎng)頁通過腳本設置 Cookie document.cookie = "test1 = hello";
// B網(wǎng)頁可以獲取到該 Cookie var otherCookie = document.cookie;
降域使不同源的iframe窗口和父窗口相互通信:如果兩個網(wǎng)頁不同源,就無法拿到對方的
DOM。典型的例子是 iframe 窗口和與父窗口無法通信。如果兩個窗口一級域名相同,只是二級域名不同,那么設置 document.domain 屬性,就可以規(guī)避同源政策,拿到
DOM。
A 網(wǎng)頁:URL: http://a.yanxin.com:8080/a.html
HTML
使用降域?qū)崿F(xiàn)跨域
script
iframe 中的 B 網(wǎng)頁:URL: http://b.yanxin.com:8080/b.html
HTML
script
postMessageHTML5為了解決跨域問題,引入了一個全新的API:跨文檔通信 API(Cross-document messaging)。
這個API為window對象新增了一個window.postMessage方法,允許跨窗口通信,不論這兩個窗口是否同源。
目的:向另一個地方傳遞數(shù)據(jù),另一個地方指的是:包含在當前頁面的
window.postMessage() 方法被調(diào)用時,會在所有頁面腳本執(zhí)行完畢之后向目標窗口派發(fā)一個 MessageEvent 消息。 * otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow:其他窗口的一個引用(相對于當前的窗口的其他窗口),比如iframe的contentWindow屬性、執(zhí)行window.open返回的窗口對象、或者是命名過或數(shù)值索引的window.frames。
message將要發(fā)送到其他 window的數(shù)據(jù)
targetOrigin:指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示無限制)或者一個URI。在發(fā)送消息的時候,如果目標窗口的協(xié)議、主機地址或端口這三者的任意一項不匹配targetOrigin提供的值,那么消息就不會被發(fā)送;只有三者完全匹配,消息才會被發(fā)送。
注意:如果你明確的知道消息應該發(fā)送到哪個窗口,那么請始終提供一個有確切值的targetOrigin,而不是*。不提供確切的目標將導致數(shù)據(jù)泄露到任何對數(shù)據(jù)感興趣的惡意站點。
示例
頁面 A: http://a.yanxin.cn:8080/a.html。
在頁面 A 中 打開頁面 B: http://b.yanxin.cn:8080/b.html
當點擊頁面 A 上的 button 時,向頁面B傳輸消息 "hello world"
HTML
script
為頁面 B 的 window 添加監(jiān)聽器
當頁面 B 收到 Message 時,在控制臺中輸出收到的消息,并提示 "hello"
CORS: Cross-Origin Resource Sharing, 跨源資源共享,是W3C的一個工作草案,定義了在必須訪問跨源資源時,瀏覽器與服務器應該如何溝通,它是一種 ajax跨域請求資源的方式,支持現(xiàn)代瀏覽器,IE支持10以上。
實現(xiàn)過程:當使用 XMLHttpRequest發(fā)送請求時,瀏覽器發(fā)現(xiàn)該請求不符合同源策略,會自動給該請求加一個請求頭:Origin,并將請求發(fā)送。服務器端收到請求后,如果確定接受請求則在返回結(jié)果中加入一個響應頭:Access-Control-Allow-Origin; 瀏覽器收到響應后判斷該相應頭中是否包含 Origin 的值,如果有則瀏覽器會處理響應,我們就可以拿到響應數(shù)據(jù),如果不包含瀏覽器直接駁回,這時我們無法拿到響應數(shù)據(jù)。整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與
實現(xiàn)CORS通信的關(guān)鍵是服務器。只要服務器實現(xiàn)了CORS接口,就可以跨源通信。
詳細流程:
1.瀏覽器發(fā)現(xiàn)這次請求不符合同源策略,就自動在頭信息之中,添加一個Origin字段。
GET /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
在上面的頭信息中,Origin字段表明了本次請求來自哪個源:協(xié)議、域名、端口。
2.該請求到達服務器后,服務器會根據(jù)這個值來判斷是否接受請求。如果Origin指定的域名在許可范圍內(nèi),服務器返回的響應,會多出幾個頭信息字段(如下所示)。如果Origin指定的源,不在許可范圍內(nèi),服務器會返回一個正常的HTTP回應。
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
3.瀏覽器收到響應后判斷該相應頭中是否包含Origin的值,如果響應的頭信息沒有包含Access-Control-Allow-Origin字段,就知道出錯了,從而拋出一個錯誤,被XMLHttpRequest的onerror回調(diào)函數(shù)捕獲,這時我們無法拿到響應數(shù)據(jù)。如果有則瀏覽器會處理響應,我們就可以拿到響應數(shù)據(jù)。
JSONP基本思想是,網(wǎng)頁通過添加一個