前後端分離 - 跨域問題

爲什麼會有跨域問題的出現?

提到跨域問題,我們就要了解一些瀏覽器的同源策略

同源策略是一個重要的安全策略,它用於限制一個origin的文檔或者它加載的腳本如何能與另一個源的資源進行交互。它能幫助阻隔惡意文檔,減少可能被攻擊的媒介。

它定義了在 協議 / 主機名 / 端口號 都相同的情況下的請求才爲同源請求:

借鑑文章

URL 結果 原因
http://store.company.com/dir2/other.html 同源 只有路徑不同
http://store.company.com/dir/inner/another.html 同源 只有路徑不同
https://store.company.com/secure.html 失敗 協議不同
http://store.company.com:81/dir/etc.html 失敗 端口不同 ( http:// 默認端口是80)
http://news.company.com/dir/other.html 失敗 主機不同

 

 

沒有同源策略的危險場景

我們在瀏覽器中登錄網站的時候,一般都是輸入一次密碼就好了,那是因爲服務器端在登錄驗證完成之後,會在響應頭中加入一個Set-Cookie,下次請求的時候,你HTTP請求的頭字段中加入這個Cookie,服務器會自動識別用戶爲驗證過的用戶,就無需再次輸入密碼驗證。

那麼問題來,如果你正在某行網站(www.mouhang.com)查詢你的“鉅額資產”,正在這個時候,你多年未見的老同學給你來了個網站(www.daohao.com),手賤的你沒有思考就點了下去。

點完你就會後悔了,同學一定是被盜號了!但是由於你像同學發的網站發送了一個請求,在沒有同源策略的情況下,帶着你Cookie的請求就發送到了www.daohao.com的網站上去,截獲了你的Cookie的非法分子,通過這個請求就可以登錄你的帳號了,你的“鉅額資產”不翼而飛。

沒錯,你遭受到了CSRF攻擊;沒有瀏覽器的保護,作爲小白的你很脆弱。

 

 

什麼時候會有跨域問題呢?

其實不是跨域就一定存在跨域問題。

這句話看起來很矛盾,其實是因爲跨域問題主要是瀏覽器對ajax請求的一種限制,雖然給我帶了一些便,但是給我們帶來了安全。

 

常見的跨域問題的解決方案?

前端:

jsonp,作爲最早的解決方案,利用script標籤可以跨域的原理實現。

侷限:1、需要服務的支持   2、只能發起 Get 請求

 

後端:

CORS,規範化的跨域請求解決方案,安全可靠。

優勢:1、在服務器端進行跨域控制,還可以自定義規則   2、支持各種請求方式

侷限:會產生額外的請求

 

 

nginx,通過反向代理,將跨域請求轉換爲非跨域請求

優勢:支持多種請求方式

侷限:需要在nginx上進行額外的配置,語義不清晰

 

解決方案

jsonp

我作爲一個後端開發人員,就不給大家分享了。

CORS

之前我寫過關於 spring boot 中通過 CROS 解決跨域問題的文章:傳送門,其實在跨域請求的方法上加上CorsOrigin註解,也可以進行簡單的跨域。

nginx

傳送門

 

CORS原理知識

瀏覽器會把ajax請求分爲兩種:簡單請求特殊請求

 

簡單請求:

請求方法是以下三種:HEAD、GET、POST

HTTP的頭信息不超過以下幾種字段:Accept、Accept-Language、Cotent-Language、Last-Event-ID、Content-Type

 

當瀏覽器檢測到ajax的請求時簡單請求的時候,會在請求頭上加一個字段 --->origin,origin中會指出當前請求屬於哪個域(協議+域名+端口)。服務會根據這個值決定是否允許其跨域。

如果允許跨域;服務器會在返回的響應頭中加入一下信息:

  • Access-Control-Allow-Origin:可接受的域,是一個具體域名或者*(代表任意域名)

  • Access-Control-Allow-Credentials:是否允許攜帶cookie,默認情況下,cors不會攜帶cookie,除非這個值是true

 

服務器要想操作cookie,需要滿足3個條件:

  • 服務的響應頭中需要攜帶Access-Control-Allow-Credentials並且爲true。

  • 瀏覽器發起ajax需要指定withCredentials 爲true

  • 響應頭中的Access-Control-Allow-Origin一定不能爲*,必須是指定的域名

 

需要注意的是,CORS需要瀏覽器和服務器的支持,目前的話,貌似所有瀏覽器都支持該功能,瀏覽器的版本不能低於10

之前我寫過關於 spring boot 中通過 CROS 解決跨域問題的文章:傳送門 ,其實我們也可以通過 在被跨域請求的方法上加上 @CorsOrigin 註解進行簡單的跨域操作。

 

特殊請求:

不符合簡單請求的條件,會被瀏覽器判定爲特殊請求,,例如請求方式爲PUT。

預檢請求

特殊請求會在正式通信之前,增加一次HTTP查詢請求,稱爲"預檢"請求(preflight)。

瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些HTTP動詞和頭信息字段。只有得到肯定答覆,瀏覽器纔會發出正式的XMLHttpRequest請求,否則就報錯。

預檢請求的樣板

OPTIONS /cors HTTP/1.1
Origin: http://www.eric.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.leyou.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

服務器對預檢請求進行檢測,如果可以跨域,會給客戶端一個響應,響應樣板

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2019 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://www.eric.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 1728000
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

 

簡做總結,如果不足,歡迎指出!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章