在我們的Rails應用程序中,我們使用protect_from_forgery
來防止CSRF。Rails protect_from_forgery如果空閒時打破登錄表單
但是,我們發現,如果用戶訪問登錄頁面,然後在應用程序會話過期時間(比如說15分鐘)的時間內喝下一杯茶。登錄只是重定向回登錄頁面,無論憑證是否成功(取決於環境,我們會得到錯誤InvalidAuthenticityToken
。)嘗試再次登錄可以正常工作。它只會在用戶在頁面上的時間超過會話時間時纔會失敗。
我們認爲這很奇怪,因爲我們還沒有登錄...所以什麼會話過期?當然,即使創建並過期,也會在登錄時創建新會話。發現(看完這個後:https://nvisium.com/blog/2014/09/10/understanding-protectfromforgery/)Rails中的CSRF保護實際上使用一個會話來檢查authenticity_token
是否有效。所以基本上當會話過期時(取決於session_store
設置),令牌會過期,並且無需再次刷新頁面就無法登錄。
我們解決了這個問題:skip_before_action :verify_authenticity_token, only: [:create]
在我們的SessionsController
,但現在這意味着我們的登錄表單不再受到保護。
還有什麼其他的選擇來解決這個問題?或者,我們所用的解決方案並非如我們所想象的那樣不安全?谷歌搜索顯示這段代碼使用了很多次,但肯定這是一個壞主意?
我們其他的解決辦法是允許例外的情況發生,但是優雅地處理它:
rescue_from ActionController::InvalidAuthenticityToken do
@exception = exception.message
render 'errors/500', :status => 500, :layout => 'other'
end
雖然仍恨用戶坐在登錄頁面上比會話超時時間(在這種情況下,事實15分鐘)會導致錯誤!
另一種解決方案,我們想出了是設置session_store永遠然後手動到期的登錄會話是這樣的:
before_action :session_timeout, if: :current_user
def session_timeout
session[:last_seen_at] ||= Time.now
if session[:last_seen_at] < 15.minutes.ago
reset_session
else
session[:last_seen_at] = Time.now
end
end
你使用什麼樣的'session_store'? –