同源策略與CORS


同源策略

同源策略是瀏覽器保護用戶安全上網的重要措施,協議、域名、端口號三者相同即為同源。

不同源下,瀏覽器不允許js操作Cookie、LocalStorage、DOM等數據或頁面元素,也不允許發送ajax請求,同源下則不受影響。

下圖是在Chrom控制台中發送ajax跨域請求的報錯信息:

 

 

 

圖片中黃色部分提示響應被阻止,說明在跨域的情況下,請求依然發送到了服務器且服務器返回了數據,只是被瀏覽器攔下了。

對於跨域問題可以使用CORS來解決,使用CORS時,HTTP請求分為兩種情況:簡單請求與復雜請求。

簡單請求

滿足以下三點即為簡單請求:

  • HTTP請求方法為GET、POST或HEAD
  • HTTP請求頭只能包含Accept, Accept-Language, Content-Language, Content-TypeLast-Event-ID
  • ContentType的值只能為以下三種:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

復雜請求

除簡單請求之外即為復雜請求。瀏覽器在發送復雜請求前會先發送Preflight request(預檢請求),即發送OPTIONS請求。注意是瀏覽器發送的,用戶無感。

 

 

 

預檢請求頭包含兩個特定字段:

  • Access-Control-Request-Method
    表示后續請求會用到的HTTP方法,該字段必選
  • Access-Control-Request-Headers
    后續請求中所設置的請求頭部信息,注意,這里不包含瀏覽器默認設置的頭部字段,如:User-Agent。該字段可不發送。

服務器會檢查對預檢請求中的OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段值,並返回正常的HTTP響應。
瀏覽器根據返回信息判斷后續請求是否符合服務器端跨域要求,不符合則拋出錯誤信息。通過預檢請求后,則發送后續請求,此時和簡單請求無差別。

服務器配置CORS的幾個字段

  • Access-Control-Allow-Origin
    必選,設置允許哪些源訪問服務器資源
  • Access-Control-Allow-Methods
    必選,設置允許哪些HTTP方法
  • Access-Control-Request-Headers
    設置HTTP請求頭中包含哪些字段,如果瀏覽器請求包括Access-Control-Request-Headers字段,則必選

以上三個字段為常用字段,其余字段配置參考:CORS policy options

withCredentials與Cookie的跨域問題

Cookie受到同源策略的限制沒有那么嚴格,默認情況下,只要發送請求方所在域與Cookie的Domain值相同即可將cookie發送至服務器端,無需考慮協議和端口號。在默認情況下,客戶端發起的HTTP請求會帶上目標域的Cookie,但無法攜帶其它屬於其它的域Cookie。

我們可以借助XMLHttpRequest對象的withCredentials屬性及CORS的Access-Control-Allow-Credentials二者來實現跨域的Cookie發送和寫入。

var xhr=new XMLHttpRequest();
xhr.open('GET','http://www.target.com:8093/api/GetAllProductType');
xhr.onreadystatechange=function(){
    if(xhr.readyState==4 && xhr.status==200){
        console.log(xhr.response);
    }
}
// 這里使用withCredentials屬性來發送Cookie
xhr.withCredentials=true;
xhr.send();

注意,在使用withCredentials時,服務器端不能將Access-Control-Allow-Origin的值配置為*,否則客戶端會報錯:

Access to XMLHttpRequest at ''http://www.target.com:8093/api/GetAllProductType' from origin 'http://www.request.com:8094' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

一個問題

上周在ASP.NET Web API 2中使用CORS,報錯:The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed。原因是服務器端配置了兩次CORS,導致返回了兩個Access-Control-Allow-Origin:*但瀏覽器只允許一個。

經過排查發現在Web.config文件中也配置了CORS,與代碼中的配置重復,注釋掉之后問題解決。該問題參考了:stackoverflow上的回答。

小結

同源策略是瀏覽器為保障用戶(數據)安全而對JS功能進行一定限制。畢竟HTML與CSS只負責網頁結構與樣式,不具備操作頁面元素及與服務器交互的功能。

離開瀏覽器環境后跨域問題也就不復存在。

嚴格的限制會導致一些不便,故同源策略開了幾個口子:

  • Cookie共享
    子域名可以共享父級域名的cookie

  • 嵌入式資源獲取
    <script>,<img>,<link>等標簽獲取資源不受同源策略限制,這也是JSONP實現跨域的原理

常用處理跨域請求的方式有JSONP和CORS:

  • JSONP
    需要前后端協作處理且只支持GET請求
    不是標准規范
    對老式瀏覽器友好(這里想到了老古董IE:)

  • CORS
    支持GET、POST、PUT、DELETE等多種請求
    服務器端配置簡單且不需要前端寫額外的代碼
    目前主流瀏覽器均支持CORS規范

推薦閱讀

瀏覽器家族的安全反擊戰

Enable Cross-Origin Requests (CORS) in ASP.NET Core

前后端分離 | 關於登錄狀態那些事

Cross-Origin Resource Sharing (CORS)

Cookie中的幾個概念


免責聲明!

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



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