老問題,但安全性很重要,我覺得它應該得到一個完整的答案。正如在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 Cookie發回給已具有已驗證會話的瀏覽器,而不是針對每個請求。這將阻止提交有效的登錄,而不使用CSRF元標記。
我鏈接的頁面不同意:「某些瀏覽器插件和HTTP重定向的組合可以用來欺騙用戶的瀏覽器進行跨域請求,其中包括攻擊者指定的任意HTTP標頭,攻擊者可以利用它來欺騙ajax和API請求,並繞過內置的CSRF保護併成功攻擊應用程序。「 –
「這與API無關,因爲它們不在瀏覽器中運行」:有時,瀏覽器*是API的客戶端 - 即, – antinome
http://stackoverflow.com/questions/9362910/rails -warning -cant-verify-csrf-token-authenticity-for-json-devise-requests/10049965#10049965 – montrealmike