目錄javascript
CORS跨域資源共享html
簡單跨域請求java
非簡單請求python
CORS的安全問題linux
有關於瀏覽器的同源策略和如何跨域獲取資源,傳送門——> 瀏覽器同源策略和跨域的實現方法程序員
同源策略(SOP)限制了應用程序之間的信息共享,而且僅容許在託管應用程序的域內共享。這有效防止了系統機密信息的泄露。但與此同時,也帶來了另外的問題。隨着Web應用程序和微服務使用的日益增加,出於實用目的每每須要將信息從一個子域傳遞到另外一個子域,或者在不一樣域之間進行傳遞(例如將訪問令牌和會話標識符,傳遞給另外一個應用程序)。web
爲了容許跨域通訊,開發人員必須使用不一樣的技術來繞過SOP並傳遞敏感信息,以致於現今也成爲了一個棘手的安全問題。所以,爲了在不影響應用程序安全狀態的狀況下實現信息共享,在HTML5中引入了跨源資源共享(CORS)。但問題也隨之而來,許多人爲了方便乾脆直接使用默認的配置,或是因爲缺少對此的瞭解而致使了錯誤的配置。sql
跨域資源共享(CORS)是一種放寬同源策略的機制,它容許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制,以使不一樣的網站能夠跨域獲取數據。json
咱們先來簡單分析一下CORS跨域獲取資源的過程:後端
CORS定義了兩種跨域請求:簡單請求 和 非簡單請求。簡單跨域請求就是使用設定的請求方式請求數據,而非簡單跨域請求則是在使用設定的請求方式請求數據以前,先發送一個OPTIONS預檢請求,驗證請求源是否爲服務端容許源。只有"預檢"經過後纔會再發送一次請求用於數據傳輸。
當咱們須要發送一個跨域請求的時候,瀏覽器會首先檢查這個請求,若是它是簡單跨域請求,瀏覽器就會馬上發送這個請求。若是它是非簡單跨域請求,這時候瀏覽器不會立刻發送這個請求,而是有一個跟服務器預檢驗證的過程。
(1) 請求方法是如下三種方法之一: HEAD GET POST (2)HTTP的頭信息不超出如下幾種字段: Accept Accept-Language Content-Language Last-Event-ID Content-Type:application/x-www-form-urlencoded、 multipart/form-data、text/plain
只有同時知足以上兩個條件時,纔是簡單請求,不然爲非簡單請求。
瀏覽器判斷該請求爲簡單請求時,會在Request Header中添加 Origin 字段,它表示咱們的請求源。
以下,簡單請求頭:
CORS服務端會將該字段做爲跨源標誌。CORS接收到這次請求後, 首先會判斷Origin是否在容許源(由服務端決定)範圍以內。
若是Origin指定的源在許可範圍內,即驗證經過,服務端會在Response Header 添加下面幾個字段
Origin
字段的值,要麼是一個*
,表示接受任意域名的請求。true時
,即表示服務器明確許可,Cookie能夠包含在請求中,一塊兒發給服務器。這個值也只能設爲true
,若是服務器不要瀏覽器發送Cookie,刪除該字段便可XMLHttpRequest
對象的getResponseHeader()
方法只能拿到6個基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。若是想拿到其餘字段,就必須在Access-Control-Expose-Headers
裏面指定。以下,CROS服務端的迴應:
若是Origin
指定的源不在許可範圍內,即驗證失敗,服務器也會返回一個正常的HTTP迴應。瀏覽器發現,這個迴應的頭信息中的Access-Control-Allow-Origin
字段不包含訪問源,就知道出錯了,從而拋出同源檢測異常的錯誤。注意,這種錯誤沒法經過狀態碼識別,由於HTTP迴應的狀態碼有多是200。
上面說到,CORS請求默認不發送Cookie和HTTP認證信息。若是要把Cookie發到服務器,一方面要服務器贊成,指定Access-Control-Allow-Credentials
字段。
Access-Control-Allow-Credentials:true
另外一方面,開發者必須在AJAX請求中打開withCredentials
屬性
var xhr = new XMLHttpRequest(); xhr.withCredentials = true;
不然,即便服務器贊成瀏覽器發送Cookie,瀏覽器也不會發送。或者,服務器要求設置Cookie,瀏覽器也不會處理。
可是,若是省略withCredentials
設置,有的瀏覽器仍是會一塊兒發送Cookie。這時,能夠顯式關閉withCredentials
xhr.withCredentials = false;
須要注意的是,若是要發送Cookie,即Access-Control-Allow-Credentials:true時,Access-Control-Allow-Origin
就不能設爲星號,必須指定明確的、與請求網頁一致的域名。同時,Cookie依然遵循同源政策,只有用服務器域名設置的Cookie纔會上傳,其餘域名的Cookie並不會上傳,且(跨源)原網頁代碼中的document.cookie
也沒法讀取服務器域名下的Cookie。
總結:簡單請求只須要CORS服務端在接受到攜帶Origin字段的跨域請求後,在response header中添加Access-Control-Allow-Origin等字段給瀏覽器作同源判斷。
非簡單請求是那種對服務器有特殊要求的請求,好比請求方法是PUT
或DELETE
,或者Content-Type
字段的類型是application/json
。非簡單請求的CORS請求,會在正式通訊以前,增長一次OPTIONS方法的預檢請求。
瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可使用哪些HTTP動詞和頭信息字段。只有獲得確定答覆,瀏覽器纔會發出正式的XMLHttpRequest
請求,不然就報錯。
下面簡單分析一下非簡單跨域請求的過程。瀏覽器先發送一個OPTIONS方法的預檢請求。帶有以下字段:
而後若是服務器配置了CORS,會返回對應對的字段,具體字段含義在返回結果是一併解釋。
以下,OPTIONS預檢的請求與相應
而後瀏覽器再根據服務器的返回值判斷是否發送非簡單請求。而後服務器處理完請求以後,會再返回結果中加上以下控制字段:
而後瀏覽器經過返回結果的這些控制字段來決定是將結果開放給客戶端腳本讀取仍是屏蔽掉。若是服務器沒有配置CORS,返回結果沒有控制字段,瀏覽器會屏蔽腳本對返回信息的讀取,並報出同源檢測異常的錯誤!
經過上面敘述,咱們得知藉助CORS咱們沒必要關心發出的請求是否跨域,瀏覽器會幫咱們處理這些事情,可是服務端須要支持CORS,服務端實現CORS的原理也很簡單,在服務端徹底能夠對請求作上下文處理,已達到接口容許跨域訪問的目的。
固然,也有不少第三方的CORS插件,例如:Spring MVC 在4.2以上版本也支持了CORS配置,這樣,服務端也無需本身操心了!
CORS很是有用,能夠共享許多內容,不過這裏存在風險。由於它徹底是一個盲目的協議,只是經過HTTP頭來控制的。那麼,CORS跨域資源共享漏洞是怎麼發生的呢?因爲程序員配置不當,Origin源不嚴格,從而形成跨域問題。
由以上可知,網站能夠經過發送如下HTTP響應頭部來啓用CORS:
Access-Control-Allow-Origin: https://example.com
這樣的話,就能夠容許指定的源(http://example.com)來跨域請求服務器端的資源,而且服務器會響應。在默認狀況下,發送跨域請求時不會攜帶cookie或其餘憑據。所以,它不能用於竊取與用戶相關的敏感信息(如CSRF令牌)。不過,網站服務器可使用如下頭部來啓用憑據傳輸:
Access-Control-Allow-Credentials:true
這樣瀏覽器在請求數據的時候就須要帶上cookie。
實現對單個域的信任是很是容易的事情。不過,若是須要信任多個域的話,那該怎麼辦呢?根據相關規範的建議,只需列出相關的域,並用空格加以分隔便可,例如:
Access-Control-Allow-Origin:http://a.example.com http://example.com
可是,沒有哪一個瀏覽器真正支持這一特性。
因而,咱們能夠經過使用通配符來信任全部子域,具體方法是:
Access-Control-Allow-Origin: *.example.com
但是有一些偷懶的程序員,將Access-Control-Allow-Origin設置爲容許來自全部域*的跨域請求。
Access-Control-Allow-Origin:*
這樣,全部的網站均可以對其進行跨域資源請求了,這是很是危險的。不過先別高興的太早。其實這裏在設計的時候有一個很好的限制。xmlhttprequest發送的請求須要使用 "withCredentials" 來帶上Cookie,若是一個目標域設置成了容許任意域的跨域請求,這個請求又帶着 Cookie 的話,這個請求是不合法的。(就是若是須要實現帶 Cookie 的跨域請求,CORS服務端須要明確的配置容許來源的域,使用任意域的配置是不合法的)瀏覽器會屏蔽掉返回的結果。Javascript 就無法獲取返回的數據了。這是CORS模型最後一道防線。假如沒有這個限制的話,那麼 Javascript 就能夠獲取返回數據中的 Cookie 和 CSRF Token,以及各類敏感數據。這個限制極大的下降了CORS的風險。
以下,這是不容許的:
Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true
這時,將在瀏覽器控制檯中收到錯誤消息:當憑證標誌爲true時,沒法在Access-Control-Allow-Origin中使用通配符(各個瀏覽器報錯顯示的不同)。
那麼,CORS的漏洞到底出如今哪裏呢?
1:CORS服務端的 Access-Control-Allow-Origin 設置爲了 *,而且 Access-Control-Allow-Credentials 設置爲false,這樣任何網站均可以獲取該服務端的任何數據了。
2:有一些網站的Access-Control-Allow-Origin他的設置並非固定的,而是根據用戶跨域請求數據的Origin來定的。這時,無論Access-Control-Allow-Credentials 設置爲了 true 仍是 false。任何網站均可以發起請求,並讀取對這些請求的響應。意思就是任何一個網站均可以發送跨域請求來得到CORS服務端上的數據。
下面的代碼是經過AJAX來跨域請求獲取服務端的數據
<html lang="en"> <head> <meta charset="UTF-8"> <title>Ajax</title> <script type="text/javascript"> function foo(){ var xmlhttp=new XMLHttpRequest(); var url="http://127.0.0.1/1.txt"; //要跨域訪問的資源 xmlhttp.open("POST",url,true); //xmlhttp.setRequestHeader('X-PINGOTHER','AAAA'); //自定義頭部,若是這樣的話,就屬於非簡單請求了 //xmlhttp.setRequestHeader('Content-Type','text/xml'); //自定義頭部,若是這樣的話,就屬於非簡單請求了 xmlhttp.send(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById("my").innerHTML=xmlhttp.responseText; } } } </script> </head> <body> <button id="btn" οnclick="foo()">肯定</button> <p id="my">hello,word!</p> </body> </html>