跨域資源共享(CORS)

什麼是瀏覽器的同源策略

同源策略限制了一個源(origin)中加載文本或腳本與來自其它源(origin)中資源的交互方式。javascript

同源定義

若是兩個頁面擁有相同的協議(protocol),端口(若是指定),和主機,
那麼這兩個頁面就屬於同一個源(origin)。

下表給出了相對http://store.company.com/dir/page.html同源檢測的示例:html

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://news.company.com/dir/other.html 失敗 主機名不一樣

變動源

頁面能夠改變自己的源,但會受到一些限制。腳本能夠設置document.domain 的值爲當前域的一個後綴,若是這樣作的話,短的域將做爲後續同源檢測的依據。java

例如,假設在 http://store.company.com/dir/other.html中的一個腳本執行了下列語句:web

document.domain = "company.com";

這條語句執行以後,頁面將會成功地經過對 http://company.com/dir/page.html 的同源檢測。ajax

瀏覽器單獨保存端口號。任何的賦值操做,包括document.domain = document.domain都會以null值覆蓋掉原來的端口號。 所以company.com:8080頁面的腳本不能僅經過設置document.domain = "company.com"就能與company.com通訊。賦值時必須帶上端口號,以確保端口號不會爲null。shell

附註:使用document.domain來讓子域安全地訪問其父域,須要同時將子域和父域的document.domain設置爲相同的值。必需要這麼作,即便是簡單的將父域設置爲其原來的值。沒有這麼作的話可能致使受權錯誤。後端

CORS

可是實踐中有一些場景須要跨域的讀寫,因此出現了一些hack的方式來跨域。好比在同域內作一個代理,JSON-P等。 但這些方式都存在缺陷,沒法完美的實現跨域讀寫。因此在XMLHttpRequest v2標準下,提出了CORS(Cross Origin Resourse-Sharing)的模型,試圖提供安全方便的跨域讀寫資源。目前主流瀏覽器均支持CORS。跨域

技術原理

CORS定義了兩種跨域請求,簡單跨域請求和非簡單跨域請求。瀏覽器

當一個跨域請求發送簡單跨域請求包括緩存

  • 請求方法爲HEAD,GET,POST;
  • 請求頭只有4個字段,Accept,Accept-Language,Content-Language,Last-Event-ID;
  • 若是設置了Content-Type,則其值只能是application/x-www-form-urlencoded,multipart/form-data,text/plain。

提及來比較彆扭,簡單的意思就是設置了一個白名單,符合這個條件的纔是簡單請求。其餘不符合的都是非簡單請求。以下圖所示:

image

之因此有這個分類是由於瀏覽器對簡單請求和非簡單請求的處理機制是不同的。當咱們須要發送一個跨域請求的時候,瀏覽器會首先檢查這個請求,若是它符合上面所述的簡單跨域請求,瀏覽器就會馬上發送這個請求。

若是瀏覽器檢查以後發現這是一個非簡單請求,好比請求頭含有X-Forwarded-For字段。這時候瀏覽器不會立刻發送這個請求,而是有一個preflight,跟服務器驗證的過程。瀏覽器先發送一個options方法的預檢請求。下圖是一個示例。若是預檢經過,則發送這個請求,不然就不拒絕發送這個跨域請求。

image

下面詳細分析一下實現安全跨域請求的控制方式。先看一下非簡單請求的預檢過程。

  • 瀏覽器先發送一個options方法的請求。帶有以下字段:
Origin: 普通的HTTP請求也會帶有,在CORS中專門做爲Origin信息供後端比對,代表來源域。
Access-Control-Request-Method: 接下來請求的方法,例如PUT, DELETE等等
Access-Control-Request-Headers: 自定義的頭部,全部用setRequestHeader方法設置的頭部都將會以逗號隔開的形式包含在這個頭中
  • 而後若是服務器配置了cors,會返回對應對的字段,具體字段含義在返回結果是一併解釋。
Access-Control-Allow-Origin: 
Access-Control-Allow-Methods:
Access-Control-Allow-Headers:
  • 而後瀏覽器再根據服務器的返回值判斷是否發送非簡單請求。簡單請求前面講過是直接發送,只是多加一個origin字段代表跨域請求的來源。而後服務器處理完請求以後,會再返回結果中加上以下控制字段:
Access-Control-Allow-Origin: 容許跨域訪問的域,能夠是一個域的列表,也能夠是通配符"*"。這裏要注意Origin規則只對域名有效,並不會對子目錄有效。即http://foo.example/subdir/ 是無效的。可是不一樣子域名須要分開設置,這裏的規則能夠參照同源策略
Access-Control-Allow-Credentials: 是否容許請求帶有驗證信息,這部分將會在下面詳細解釋
Access-Control-Expose-Headers: 容許腳本訪問的返回頭,請求成功後,腳本能夠在XMLHttpRequest中訪問這些頭的信息(貌似webkit沒有實現這個)
Access-Control-Max-Age: 緩存這次請求的秒數。在這個時間範圍內,全部同類型的請求都將再也不發送預檢請求而是直接使用這次返回的頭做爲判斷依據,很是有用,大幅優化請求次數
Access-Control-Allow-Methods: 容許使用的請求方法,以逗號隔開
Access-Control-Allow-Headers: 容許自定義的頭部,以逗號隔開,大小寫不敏感

而後瀏覽器經過返回結果的這些控制字段來決定是將結果開放給客戶端腳本讀取仍是屏蔽掉。若是服務器沒有配置cors,返回結果沒有控制字段,瀏覽器會屏蔽腳本對返回信息的讀取。

安全隱患

你們注意這個流程。服務器接收到跨域請求的時候,並無先驗證,而是先處理了請求。因此從某種程度上來講。在支持cors的瀏覽器上實現跨域的寫資源,打破了傳統同源策略下不能跨域讀寫資源。

再一個就是若是程序猿偷懶將Access-Control-Allow-Origin設置爲容許來自全部域的跨域請求。那麼cors的安全機制幾乎就無效了。不過先別高興的太早。其實這裏在設計的時候有一個很好的限制。xmlhttprequest發送的請求須要使用「withCredentials」來帶上cookie,若是一個目標域設置成了容許任意域的跨域請求,這個請求又帶着cookie的話,這個請求是不合法的。(就是若是須要實現帶cookie的跨域請求,須要明確的配置容許來源的域,使用任意域的配置是不合法的)瀏覽器會屏蔽掉返回的結果。javascript就無法獲取返回的數據了。這是cors模型最後一道防線。假如沒有這個限制的話,那麼javascript就能夠獲取返回數據中的csrf token,以及各類敏感數據。這個限制極大的下降了cors的風險。

攻擊模型

image

從思路上講,有兩種類型的攻擊方式。

  • 一種是在攻擊者本身控制的網頁上嵌入跨域請求,用戶訪問連接,執行了跨域請求,從而攻擊目標,好比訪問了內網敏感資源。
  • 另一種是正常的網頁被嵌入了到攻擊者控制頁面的跨域請求,從而劫持用戶的會話。

攻擊模型一

  • 複雜csrf。傳統的csrf都是利用html標籤和表單來發送請求。沒有辦法實現一些複雜步驟的csrf,好比模擬購物,先加購物車,結算,填寫信息,等等。好比上傳文件。具體能夠參考利用csrf上傳文件
  • 訪問內網敏感資源。這個在必定的條件下是能夠實現的。好比內網的服務器配置了
Access-Control-Allow-Origin: * 容許任何來自任意域的跨域請求

用戶訪問惡意網頁的時候,執行了到內網服務器192.168.1.123/password.txt的請求,腳本在接收到服務器返回以後,將內容發送到攻擊者的服務器上。

攻擊模型二

  • 交互式xss。參考揭密HTML5帶來的攻擊手法中講到的shell of the future工具。經過cors,繞過一些反會話劫持的方法,如HTTP-Only限制的cookie,綁定IP地址的會話ID等,劫持用戶會話。
  • 程序猿在寫ajax請求的時候,對目標域限制不嚴。有點相似於url跳轉。facebook出現過這樣一個案例。javascript經過url裏的參數進行ajax請求。經過控制這個參數實現注入攻擊。

解決思路

目前來講,解決思路有兩種

  • 設置容許訪問的域
Access-Control-Allow-Origin: allow.domain.com
  • 設置token,即每次請求的時候,都須要帶上token進行校驗

引入文章

相關文章
相關標籤/搜索