2016-11-11 2 views
12

В нашем 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 
+0

Какой тип 'session_store' вы используете? –

ответ

8

так, что сессия истекает?

Сеанс Речь идет о Rails сессии (см What are Sessions? в Ruby on Rails Security Guide), которая представляет собой облегченный абстракции данных для хранения, которая сохраняется произвольное состояние по HTTP запросов (в зашифрованном куки по умолчанию, другими реализациями сеанса хранения также можно настроить). Состояние сеанса может содержать идентификатор пользователя с аутентификацией, но его также можно использовать для других целей.

В этом случае сеанс не используется для аутентификации пользователя, а для хранения временного токена аутентификации как части функции безопасности Rails, которая защищает ваш сайт от атак Cross-Site Request Forgery (CSRF) при POST (или других не- -GET).

Rails API documentation описывает эту функцию более подробно: действия

контроллера защищены от Cross-Site Request подлога атак (CSRF) путем включения маркеров в оказанном HTML для вашего приложения. Этот токен хранится как случайная строка в сеансе, к которой злоумышленник не имеет доступа. Когда запрос достигает вашего приложения, Rails проверяет полученный токен с токеном в сеансе.

Смотрите также Cross-Site Request Forgery раздел Ruby on Rails Security Guide для более полного обзора того, что атака CSRF, и как на основе сеанс подлинности лексемы проверки защищает от него.

Какие еще варианты можно исправить?

  • Увеличение длительности действия Рельсы истечения времени сеанса (например, путем увеличения длительности опциона expire_after передается вашему cookie_store инициализаторе или вынимая вариант полностью, чтобы сделать сеанс никогда не истекает).

  • Вместо истечения срока действия сеанса печенья истекает анонимов сеансов, используйте :timeoutable модуль Devise «s:

    devise :timeoutable, timeout_in: 15.minutes 
    

Или решение, которое мы использовали не как небезопасным, так как мы думать?

Настройка Rails для пропуска verify_authenticity_token обратного вызова отключает защиту от CSRF для этого конкретного действия контроллера, что делает действие уязвимым для атак CSRF.

Так перефразировать ваш вопрос, является отключением защиты от CSRF толькодля SessionsController#create действий еще небезопасного в каком-либо значительном/значимом смысле? Хотя это зависит от вашей заявки, вообще да, я так считаю.

Рассмотрим такой сценарий:

CSRF нападение SessionsController#create позволит злоумышленнику злонамеренно прямой браузер жертвы для входа в учетную запись пользователя под контролем злоумышленника. В следующий раз, когда жертва посетила ваш сайт (например, при перенаправлении злоумышленником), их браузер все равно мог войти в контролируемую атакующую учетную запись. Затем жертва могла бессознательно передавать конфиденциальные личные данные или выполнять чувствительные действия на вашем веб-сайте, которые могут быть прочитаны злоумышленником.

Хотя этот сценарий может быть менее явно опасным, чем то, что может произойти, если защита CSRF была отключена на других более чувствительных/разрушительных действиях контроллера, она по-прежнему предоставляет достаточно потенциальную проблему с правами пользователя/данных, которая, по моему мнению, является небезопасной достаточно, чтобы рекомендовать против, отключив защиту по умолчанию.

+0

Отличный ответ, спасибо! Похоже, что это немного компромисс ... либо отключите токен, либо откройте себя для атаки CSRF, либо продлите/отключите срок действия сессии, а затем откройте себя для других проблем безопасности. – Cameron

+0

Одним из решений, которое мы имели, было вручную уничтожить сеансы для авторизации, но разрешить другим сеансам неограниченное время. См. Обновленное сообщение. – Cameron

+1

@Cameron, если вы продлеваете срок действия cookie-сессии cookie, вы должны использовать модуль 'timeoutable' от Devise для завершения сеансов входа в систему без дополнительного кода:' devise: timeoutable, timeout_in: 15.minutes'. – wjordan

1
InvalidAuthenticityToken 

Эта ошибка возникает, когда «токен аутентификации», созданный в процессе рендеринга (форма входа), уже истек.

Есть только два способа решения этой проблемы.

  • Настройка Rails для пропуска verify_authenticity_token для контроллера # действия - небезопасной, как уже упоминалось в вопросе
  • (только левый путь) Автоматическая перезагрузка экрана (логин и пароль экрана) всякий раз, когда такое исключение встречается.

Найти модифицированный код для того же самого и добавить в application_controller.rb обобщить решение для всего приложения.

rescue_from ActionController::InvalidAuthenticityToken do 
    redirect_to root_url 
end 
1

Другим вариантом было бы включить некоторые JS на странице, которая будет автоматически перезагружать некоторое время до истечения срока действия маркера (и, следовательно, держать маркер аутентификации действителен).

Возможно, вы захотите проверить действие мыши/клавиатуры перед перезагрузкой в ​​случае, если пользователь просто заполняет форму.

Похоже, что самым большим недостатком этой опции будет тот факт, что JS отделен от фактического количества времени, когда токен аутентификации действителен ... Таким образом, это может оказаться проблемой обслуживания, если вы измените время ожидания длительность часто.

Смежные вопросы