В нашем Rails-приложении мы используем protect_from_forgery
для предотвращения CSRF.Rails protect_from_forgery прерывает регистрационную форму, если idle
Однако мы обнаружили, что если пользователь посещает страницу входа в систему, а затем уходит, чтобы выпить чашку чая в течение срока действия сеанса приложения (скажем, 15 минут). Вход просто перенаправляется на страницу входа, независимо от успешных учетных данных или нет (в зависимости от среды мы получаем ошибку InvalidAuthenticityToken
.) Пытаться войти в систему снова отлично работает. Он терпит неудачу, если пользователь находится на странице дольше, чем время сеанса.
Мы думали, что это было странно, потому что мы еще не вошли в систему ... так какая сессия заканчивается? и, конечно, новый сеанс создается при входе в систему, даже если он был создан и истек. Оказывается (после прочтения этого: https://nvisium.com/blog/2014/09/10/understanding-protectfromforgery/) защита CSRF в Rails фактически использует сеанс для проверки authenticity_token
. Таким образом, в основном токен истекает, когда сеанс истекает (в зависимости от настройки session_store
), и вы не можете войти в систему, не обновляя страницу еще раз.
Мы решили это сделать: skip_before_action :verify_authenticity_token, only: [:create]
в нашем SessionsController
, но теперь это означает, что наша форма для входа в систему больше не защищена.
Какие еще варианты можно исправить? Или это решение, которое мы использовали не так неуверенно, как мы думаем? Googling показывает, что эта строка кода используется много раз, но, конечно, это плохая идея?
другое Наше решение было разрешить исключение произойдет, но справиться с этим изящно:
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' вы используете? –