2011-09-29 63 views
40

早在2011年2月,Rails就被更改爲require the CSRF token for all non-GET請求,即使是API端點的請求也是如此。我理解爲什麼這是瀏覽器請求的重要變化的解釋,但該博客文章沒有提供關於API如何處理更改的任何建議。未禁用CSRF保護的Rails API設計

我對禁用某些操作的CSRF保護不感興趣。

API應該如何處理這種變化?是否期望API客戶端向API發出GET請求以獲取CSRF令牌,然後在該會話期間的每個請求中包含該令牌?

看起來,令牌不會從一個POST更改爲另一個。假設令牌在會話期間不會改變是否安全?

當會話過期時,我不喜歡額外的錯誤處理,但我認爲它比在每個POST/PUT/DELETE請求之前獲取令牌要好。

回答

4

Rails使用「默認安全」約定。跨網站或跨會話請求僞造要求用戶擁有瀏覽器和另一個受信任的網站。這與API無關,因爲它們不會在瀏覽器中運行,也不會維護任何會話。因此,您應該禁用API的CSRF。

當然,您需要通過要求HTTP身份驗證或自定義API標記或OAuth解決方案來保護您的API。

+2

我鏈接的頁面不同意:「某些瀏覽器插件和HTTP重定向的組合可以用來欺騙用戶的瀏覽器進行跨域請求,其中包括攻擊者指定的任意HTTP標頭,攻擊者可以利用它來欺騙ajax和API請求,並繞過內置的CSRF保護併成功攻擊應用程序。「 –

+9

「這與API無關,因爲它們不在瀏覽器中運行」:有時,瀏覽器*是API的客戶端 - 即, – antinome

+1

http://stackoverflow.com/questions/9362910/rails -warning -cant-verify-csrf-token-authenticity-for-json-devise-requests/10049965#10049965 – montrealmike

41

老問題,但安全性很重要,我覺得它應該得到一個完整的答案。正如在question中討論的那樣,即使使用API​​,CSRF仍然存在一些風險。是的,瀏覽器在默認情況下應該防範這種情況,但由於您沒有完全控制用戶安裝的瀏覽器和插件,所以在您的API中仍應被視爲防止CSRF的最佳做法。

我有時看到它的做法有時是從HTML頁面本身解析CSRF元標記。我不太喜歡這一點,因爲它不適合很多單頁+ API應用程序的工作方式,我認爲CSRF令牌應該在每個請求中發送,而不管它是HTML,JSON還是XML。

所以我建議通過一個後置過濾器爲所有請求傳遞CSRF令牌作爲cookie或標頭值。該API可以簡單地重新提交,作爲Rails已經檢查的標題值X-CSRF-Token

這是我如何與AngularJS做到了:

# In my ApplicationController 
    after_filter :set_csrf_cookie 

    def set_csrf_cookie 
    if protect_against_forgery? 
     cookies['XSRF-TOKEN'] = form_authenticity_token 
    end 
    end 

AngularJS automatically looks for a cookie命名XSRF-TOKEN但隨時將其命名爲任何你想要你的目的。然後,當您提交POST/PUT/DELETE時,您應該設置Rails自動查找的標題屬性X-CSRF-Token

不幸的是,AngualrJS已經以X-XSRF-TOKEN的標題值發回了XSRF-TOKEN cookie。人們很容易忽略Rails的默認行爲ApplicationController這樣,以適應這一點:

protected 

    def verified_request? 
    super || form_authenticity_token == request.headers['X-XSRF-TOKEN'] 
    end 

對於Rails的4.2有一個內置的助手,現在用於驗證CSRF應使用。

protected 

    def verified_request? 
    super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN']) 
    end 

我希望這很有幫助。

編輯:在我提交的discussion on this for a Rails pull-request中,傳出CSRF令牌通過API登錄是一種特別糟糕的做法(例如,某人可以爲您的站點創建使用用戶憑證而不是令牌的第三方登錄名) 。所以c em不馴。這取決於你決定你的應用程序對你的擔心。在這種情況下,您仍然可以使用上述方法,但只能將CSRF Coo​​kie發回給已具有已驗證會話的瀏覽器,而不是針對每個請求。這將阻止提交有效的登錄,而不使用CSRF元標記。

+3

你的編輯至關重要:服務器應該只爲已認證的用戶設置CSRF cookie。 – brookr

+0

那麼你認爲auth的建議是什麼?只需簡單的基於表單的身份驗證,將CSRF標記像平時一樣設置在HTML中,然後使用基於標頭或基於CSRF的CSR後的API? –

+0

設置不帶'httponly'的cookie看起來並不安全。 'httponly'不會阻止JS訪問CSRF cookie?相反,如果您使用[fetch's'credentials:'same-origin''參數](例如https://github.com/github/fetch#sending-cookies),它們會與請求一起傳遞。 爲什麼使用cookie的非常規名稱?如果使用'X-CSRF-Token',ActionDispatch會自動檢查並且不會覆蓋verified_request?需要。 我建議:'餅乾[「X-CSRF令牌」] = {值:form_authenticity_token,僅Http:真正}' –