爲何使用同源策略?
一個重要緣由就是對cookie的保護,cookie 中存着sessionID 。若是已經登陸網站,同時又去了任意其餘網站,該網站有惡意JS代碼。若是沒有同源策略,那麼這個網站就能經過js 訪問document.cookie 獲得用戶關於的各個網站的sessionID。其中可能有銀行網站,經過已經創建好的session鏈接進行攻擊,這裏有一個專有名詞,CSRF,還有須要注意的是同源策略沒法徹底防護CSRF,這裏須要服務端配合。javascript
什麼是同源策略?java
URL由協議、域名、端口和路徑組成,若是兩個URL的協議、域名和端口相同,則表示他們是同源的。同源策略是瀏覽器上爲安全性考慮實施的很是重要的安全策略。限制來自不一樣源的"document",對當前"document"讀取或設置某些屬性。 在瀏覽器中,<script>、<img>、<link>、<frame>等標籤均可加載跨域資源,而不受同源策略限制,這帶"src"屬性的標籤加載時,其實是由瀏覽器發起一次GET請求,不一樣於XMLHttpRequest,他們經過src屬性加載的資源。但瀏覽器限制了JavaScript的權限,使其不能讀、寫其中返回的內容。程序員
跨域請求的安全基礎是,JavaScript沒法修改請求對象的http頭部。 若是XMLHttpRequest可以跨域請求資源,可能致使敏感信息泄露,好比CSRF的token信息,跨域
受同源策略限制的有哪些?瀏覽器
DOM、Cookie、XMLHttpRequest,還有一些第三方插件Flash、Java Applet、Sliverlight、Google Gears等都有本身的控制策略。安全
如何規避同源策略,即跨域請求?服務器
document.domain屬性cookie
若是兩個window或者frames包含的腳本能夠把domain設置成同樣的值,那麼就能夠規避同源策略,每一個window之間能夠互相溝通。例如,orders.example.com下頁面的腳本和catalog.example.com下頁面的腳本能夠設置他們的document.domain屬性爲example.com,從而讓這兩個站點下面的文檔看起來像在同源下,而後就可讓每一個文檔讀取另外一個文檔的屬性。這種方式也不是一直都有用,由於端口號是在內部保存的,有可能被保存成null。換句話說,example.com的端口號80,在咱們更新document.domain屬性的時候可能會變成null。爲null的端口可能不被認爲是80,這主要依賴瀏覽器實現。session
跨域資源共享(CORS) app
Cross-origin Resource Sharing跨資源共享,使用自定義的HTTP頭部讓瀏覽器與服務器溝通,從而決定請求和響應是否成功。這種方式使用了一個新的Origin請求頭和一個新的Access-Control-Allow-Origin響應頭擴展了HTTP。容許服務端設置Access-Control-Allow-Origin頭標識哪些站點能夠請求文件,或者設置Access-Control-Allow-Origin頭爲"*",容許任意站點訪問文件。
瀏覽器,例如Firefox3.5,Safari4,IE10使用這個頭容許跨域HTTP請求。
服務器端在HTTP的響應頭中加入(頁面層次的控制模式):
Access-Control-Allow-Origin: example.com
Access-Control-Request-Method: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization, Accept, Range, Origin
Access-Control-Expose-Headers: Content-Range
Access-Control-Max-Age: 3600
多個域名之間用逗號分隔,表示對所示域名提供跨域訪問權限。"*"表示容許全部域名的跨域訪問
客戶端能夠有兩種行爲:
1. 發送OPTIONS請求,請求Access-Control信息。若是本身的域名在容許的訪問列表中,則發送真正的請求,不然放棄請求發送。
2. 直接發送請求,而後檢查response的Access-Control信息,若是本身的域名在容許的訪問列表中,則讀取response body,不然放棄。 本質上服務端的response內容已經到達本地,JavaScript決定是否要去讀取。
跨文檔通訊(window.postMessage方法)
這種方式容許一個頁面的腳本發送文本信息到另外一個頁面的腳本中,無論腳本是否跨域。基本上,它就像是跨域的AJAX,但不是瀏覽器跟服務器之間交互,而是在兩個客戶端之間通訊。在一個window對象上調用postMessage()會異步的觸發window上的onmessage事件,而後觸發定義好的事件處理方法。一個頁面上的腳本仍然不能直接訪問另一個頁面上的方法或者變量,可是他們能夠安全的經過消息傳遞技術交流。
容許程序員跨域在兩個窗口/frames間發送數據信息。
窗口A: 發送窗口使用postMessage發送數據 window.postMessage(msg,urlOfB); 窗口B: 接收端,監聽「message」事件,
window.onmessage(event){ var data=event.data; var origin=event.origin; }
JSONP
JSONP利用<script>標籤的跨域能力實現跨域數據的訪問,請求動態生成的JavaScript腳本同時帶一個callback函數名做爲參數。其中callback函數本地文檔的JavaScript函數,服務器端動態生成的腳本會產生數據,並在代碼中以產生的數據爲參數調用callback函數。當這段腳本加載到本地文檔時,callback函數就被調用。
爲了動態實現JSONP請求,可使用Javascript動態插入<script>標籤:
<script type="text/javascript"> // this shows dynamic script insertion var script = document.createElement('script'); script.setAttribute('src', url); // load the script document.getElementsByTagName('head')[0].appendChild(script); </script>
WebSocket
現代瀏覽器容許腳本直連一個WebSocket地址而無論同源策略。然而,使用WebSocket URI的時候,在請求中插入Origin頭就能夠標識腳本請求的源。爲了確保跨站安全,WebSocket服務器必須根據容許接受請求的白名單中的源列表比較頭數據。 與JSONP方法不一樣的是,該響應函數被傳入到建立<script> 標籤的構造函數中,檢測到已經成功接受到收據的狀態後再執行函數。
document.domain + iframe (只有在主域相同的時候才能使用該方法)
location.hash + iframe
window.name + iframepostMessage(HTML5中的XMLHttpRequest Level 2中的API)