程序員應對瀏覽器同源策略的姿勢


同源策略

  瀏覽器最基本的安全規范——同源策略(Same-Origin Policy)。所謂同源是指,域名,協議,端口相同。不同源的瀏覽器腳本(javascript、ActionScript、canvas)在沒明確授權的情況下,不能讀寫對方的資源

  同源策略規定了 瀏覽器腳本互操作web數據的基本原則。

若沒有這一基本原則,那么:

        ① 某域下DOM元素被另一方任意操作、篡改, 導致頁面顯示失控

        ② 某域下的Cookie等與該域相關的密切數據可以任意讀取,導致與該域密切相關的瀏覽器cookie片段可能失真

        ③ 惡意網站能隨意執行Ajax腳本偷取隱私數據,導致該域下核心業務數據被抓取。

同源策略在實施中面臨的問題

       默認的同源策略 限制了腳本互操作其他域的能力,大棒一揮, 關閉了A站腳本正常訪問B站數據的需求

所以有以下變通方法:

① 實現CORS (Cross-Origin Resource Sharing) : 

② 使用JSONP (JSON Padding)

③ 建立一個本地代理服務器,這樣先同源訪問,由代理服務器轉發請求

以上①CORS是w3C 對於跨域請求推出的明確方案;②③方式都是一種Hack行為。

CORS跨域請求方案

W3C推出的跨域請求方案: 讓web服務器明確授權 非同源頁面腳本來訪問自己, 以Response 特定標頭 Access-Control-****-****  體現;   目前現代瀏覽器均認可並支持這些標頭。

CORS新HTTP標頭,為瀏覽器提供了在獲得許授權,腳本才能訪問其他域名頁面數據的通道。

常規的攜帶Cookie Ajax跨域Get請求

const invocation = new XMLHttpRequest();
const url = 'http://bar.other/resources/credentialed-content/';
    
function callOtherDomain(){
  if(invocation) {
    invocation.open('GET', url, true);
    invocation.withCredentials = true;   // Ajax請求默認不會發送憑據, 這里設定在Ajax跨域請求中發送憑據
    invocation.onreadystatechange = handler;
    invocation.send(); 
  }
}

CORS規范

         ① 瀏覽器發起CORS或POST請求,瀏覽器會自動攜帶Origin標頭(指示請求來自於哪個站點)

         ② Web服務器實現跨站訪問授權邏輯, 授權結果在Response中以 Access-Control--******* 標頭體現

最常見的Access-Control-Allow-Origin標頭包含  * / Origin /null  三種響應值;

當請求是攜帶憑據的跨域請求,不可囫圇吞棗地指定為*通配符,而必須指定特定Origin

         ③ 瀏覽器會遵守Access-Control--*******-- 標頭值所施加的跨域限制

GET /resources/access-control-with-credentials/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/credential.html
Origin: http://foo.example
Cookie: pageAccess=2


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT
Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2
X-Powered-By: PHP/5.2.6
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain


[text/plain payload]

 以上表示了一個常見的攜帶Cookie跨域Ajax Get請求, 其中 Access-Control-Allow-Credentials: true 指令瀏覽器可以將跨域請求的 Response 結果暴露給頁面。

預檢Preflight

        對於非簡單Ajax請求(通常是GET以外的HTTP方法,或者某些MIME類型的POST用法),CORS規范要求發起 "預檢" 請求。

 不過,這個請求不需要你手動發起,瀏覽器會自動使用OPTIONS請求方法從服務器請求支持的方法,然后,在服務器“批准”時,使用實際的HTTP請求方法發送實際請求。

下圖顯示 瀏覽器判斷 非簡單請求的邏輯圖:

下面使用POST動作發起Ajax跨域請求,同時自定義了一個request header: X-PINGOTHER, 該請求觸發瀏覽器預檢行為

const invocation = new XMLHttpRequest();
const url = 'http://bar.other/resources/post-here/';
const body = '<?xml version="1.0"?><person><name>Arun</name></person>'; function callOtherDomain(){ if(invocation) { invocation.open('POST', url, true); invocation.setRequestHeader('X-PINGOTHER', 'pingpong'); invocation.setRequestHeader('Content-Type', 'application/xml'); invocation.onreadystatechange = handler; invocation.send(body); } }

程序員調試CORS的苦惱

跨域請求發生在A--->B 兩站,作為某一方開發人員,調試CORS相對麻煩。

經過本StackOverFlow工程師的檢索,curl 工具可優雅高效模仿Ajax跨域請求:

#  http://example.com 向谷歌站點發起一個跨域Get請求

curl -H "Origin: http://example.com" --verbose \ https://www.googleapis.com/discovery/v1/apis?fields=

 從瀏覽器Network,將請求格式 以cUrl形式拷貝出來,改改。

總結

  ①  瀏覽器同源策略 作用對象是 瀏覽器腳本;

  ②  存在跨域請求的場景,某些方案是Hack行為;

  ③  W3C推出的CORS 是標准的跨域請求方案,思路是 在服務端Response標頭體現 授權, 瀏覽器遵守該授權標頭。

  ④  對於非簡單的腳本跨域請求,瀏覽器會自動發起 Option請求預檢, 大部分時候無需關注

  ⑤ 提供curl 工具幫助高效、優雅調試CORS。

 

后面會介紹瀏覽器的另一個有用的安全策略: Cookie SameSite策略。

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

https://stackoverflow.com/questions/12173990/how-can-you-debug-a-cors-request-with-curl/12179364#12179364

https://curl.haxx.se/docs/manpage.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM