爲什麼會有跨域問題的出現?
提到跨域問題,我們就要了解一些瀏覽器的同源策略。
同源策略是一個重要的安全策略,它用於限制一個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
簡做總結,如果不足,歡迎指出!