淺談同源策略
同源策略可能是現代瀏覽器中最重要的安全概念了,它在使得同一站點中各部分頁面之間基本上能夠無限制允許腳本和其他交互的同時,能完全防止不相關的網站之間的任何干涉。現在所有支持 JavaScript 的瀏覽器都會使用這個策略,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。
我們可以假設一個沒有同源策略的場景:我打開了我自己的銀行賬戶頁面,稱之為 A,之后,我又打開了另一個頁面,我們稱之為 B。如果 B 是一個惡意頁面,那么在沒有同源策略限制的前提下,它可以通過 Javascript 任意修改和訪問 A 中的任何內容。
一、什么叫做同源
首先要厘清的是,怎么樣的頁面被稱為同源的頁面——如果兩個頁面的協議、端口以及域名都相同,那這兩個頁面就被稱之為同源,如果其中有一項不同,那也將不會滿足同源的定義。下面是以 http://store.company.com/dir/page.html 這個 URL 為源的一組例子:
將表格中所有的 URL 與 http://store.company.com/dir/page.html 相比較,我們可以看到:
第一條和第二條同時滿足了協議、端口和域名相同的條件,所以是同源;
第三條因為使用的是 https 協議,協議不同,所以不是同源;
第四條因為使用了 81 端口,端口不同,所以不是同源;
第五條因為域名,也就是域名不相同,所以不是同源。
那么為什么會對于同源做出如此嚴格的限制呢,其實是否同源主要是為了防止兩類事件:
限制跨源腳本的 APIs 的訪問;
阻止跨源數據存儲的訪問。
簡單來說就是防止一個惡意界面通過惡意請求去訪問非同源的數據。在發起跨域請求的情況下,我們的瀏覽器會自動的去拒絕這些請求,即使這樣的跨域請求通過了,其返回結果也會被瀏覽器拒絕。
二、跨源網絡訪問
同源策略會對于跨域的資源和數據的訪問做出限制。其實在網上很多情況下我們都會需要加載不同源的資源,比如在個人網站中需要插入一張在公共圖床的圖片,這種情況下個人網站和公共圖床上的圖片必然是不同源的,但最后在頁面上能成功的加載圖片并且能夠看到,這又是為什么呢?
首先,通常情況下同源策略控制跨域的請求會被分為三類:
跨域寫操作( Cross-origin writes )-- 例如表單提交,通常是被允許的;
跨域讀操作( Cross-origin reads )-- 例如可以讀取嵌入圖片的高度和寬度,通常是不被允許的;
跨域資源嵌入( Cross-origin embedding )-- 例如嵌入圖片,通常是被允許的。
那么可能有哪些資源是可以被跨源嵌入的呢?
標簽嵌入跨域腳本。語法錯誤信息只能在同源腳本中捕捉到;
標簽嵌入 CSS。由于 CSS 的松散的語法規則,CSS 的跨域需要一個設置正確的 Content-Type 消息頭;
嵌入圖片;
@font-face 引入的字體。一些瀏覽器允許跨域字體( cross-origin fonts ),一些需要同源字體( same-origin fonts );
和
如果說文件類型符合以上幾種,那么其實這樣的資源是可以被跨域嵌入的?,F代瀏覽器在安全性和可用性之間選擇了一個平衡點,在遵循同源策略的基礎上,選擇性地為同源策略“開放了后門。這也解釋了為什么放在公共圖床上的圖片能夠被正確的瀏覽的問題。
三、跨域資源共享(CORS)
因為同源策略的限制,如果在腳本內發起了跨域的 HTTP 請求,是不會得到返回結果的,最常用的應該就是 XMLHttpRequest 。如果想要獲取跨域的資源,同源策略就會成為一種枷鎖,使得數據的正常交互十分麻煩。而 CORS 則解決了這個問題。
CORS 的全稱為 Cross-Origin Resource Sharing ,跨域資源共享。這是一個由一系列傳輸的 HTTP 頭組成的系統,這些 HTTP 頭用于確定阻止還是接受從該資源所在域外的另一個域的網頁上發起的對受限資源的請求。CORS 允許 Web 應用服務器進行跨域訪問控制,從而使跨域數據傳輸得以安全進行。
簡單的來說,CORS 允許在以下幾種場景中使用跨域 HTTP 請求:
由 XMLHttpRequest 或 Fetch 發起的跨域 HTTP 請求;
Web 字體( CSS 中通過 @font-face 使用跨域字體資源)。因此,網站就可以發布 TrueType 字體資源,并只允許已授權網站進行跨站調用;
WebGL 貼圖;
使用 drawImage 將 Images/video 畫面繪制到 canvas;
樣式表(使用 CSSOM)。
四、預檢請求(Preflight Request)
前面已經解釋了 CORS 會在請求 HTTP 請求中加入一些特殊的 HTTP 頭來規定特定的資源能被跨域請求,除了這些特殊的 HTTP 頭之外,CORS 利用預檢請求的方式在跨域之前對一些特定的請求進行檢查,如果檢查響應的結果沒有通過,那么跨域請求也不會發起。
預檢請求會發生在以下幾種情況中:
非 GET 和 POST 方法的請求;
在 POST 請求中 Content-Type 字段不是 application/x-www-form-urlencoded,multipart/form-data和text/plain;
發送自定義的頭信息,比如 X-PINGARUNER。
除了這些請求,還有一些請求被稱為簡單請求,簡單請求不會觸發 CORS 的預檢請求:
請求方法為下列方法之一:
GET
HEAD
POST
HTTP 首部字段僅限下面這個集合:
Accept
Accept-Language
Content-Language
Content-Type
DPR
Downlink
Save-Date
Viewport-Width
Width
Content-Type 的值僅限于下列三中:
text/plain
multipart/form-data
application/x-www-form-urlencoded
下面我們通過一個例子來了解整個預檢請求的過程(例子中的 HTTP 頭信息都經過省略,只保留關鍵的幾條字段):
如果需要向服務器發送下面這個 POST 請求,該請求會發送一個 XML 文檔,同時包含了一個自定義的請求首部字段。
POST /doc HTTP/1.1 X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Origin: Server-b.com Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
那么首先瀏覽器會判斷該請求是否是簡單請求。因為該請求的 Content-Type 為 application/xml,也包含自定義的請求首部字段,所以在真正發送該 POST 請求之前,會先發起一個預檢請求。
下面這個 OPTIONS 請求其實就是預檢請求,該請求利用 Access-Control-Request-Method 告訴服務器,接下來的實際請求的方法是 POST,再利用 Access-Control-Request-Headers 告訴服務器,這個實際請求還會包含兩個自定義請求的首部字段。
OPTIONS /resources/post-here/ HTTP/1.1 Origin: Server-b.com Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
和普通的 HTTP 請求一樣,預檢請求也會返回一個響應。在下面這個響應中,Access-Control-Allow-Origin允許了來自 http://foo.example 這個源發來的數據。Access-Control-Allow-Methods 表示允許的方法為 POST,GET ,OPTIONS。Access-Control-Allow-Headers 表示允許了自定義的首部字段。最后 Access-Control-Max-Age 表明該響應的有效時間為 86400 秒,在有效時間內,瀏覽器就不需要為同一請求再次發起預檢請求,如果該首部字段的值超過了最大有效時間,將不會生效。每個瀏覽器都會有自己的最大有效時間,設置該限制的目的是為了避免一些安全問題。
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400
最后之前的 HTTP 請求才會發送,得到最終的響應。
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://foo.example
除了簡單請求和預檢請求之外,CORS 還允許設置 HTTP cookies 和 HTTP 認證信息發送身份憑證。(黃繆華 | 天存信息)
Ref
Same-origin_policy wiki
Same-origin policy
HTTP access control (CORS)
HTTP 網站 運維 通用安全
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。