Токены CSRF не соответствуют тому, что находится в сеансе (Rails 4.1)
Мы видим неудачную и вероятную проблему аутентификации токена CSRF в браузере в нашем приложении Rails 4.1. Мы публикуем его здесь, чтобы спросить сообщество, видят ли это и другие.
Помните, что большинство инструментов отчетов об ошибках, таких как Honeybadger, автоматически подавляют ActionController::InvalidAuthenticityToken, поэтому обычно вы не видите проблему в своем инструменте отчетов об ошибках, если только вы не пытаетесь ее увидеть.
Вот проблема, и это НЕ проблема разработки - это проблема производства, которая еще не диагностирована.
Исключением, которое мы видим, является просто ActionController::InvalidAuthenticityToken при обычных входах на наш сайт. После тщательного изучения authenticity_token, отправленного формой, и _csrf_token сеанса (мы используем active_record_store в качестве настройки session_store), они просто не совпадают. При непосредственном рассмотрении я могу сделать вывод только, что это абсолютно разные токены, но я не знаю почему.
Это не простой вопрос для начинающих разработчиков, пожалуйста, НЕ отвечайте с основными ответами о том, как токен CSRF должен передаваться от клиента к серверу, или как пропустить защиту от подделки на моих контроллерах. Мне не интересно слышать от кого-либо из этих двух ответов: вы не знаете, о чем говорите, и не понимаете глубины и сложности вопроса. Я заинтересован только в том, чтобы услышать от людей с сайтами с большим трафиком, которые могут подтвердить, что это происходит с незначительным числом посетителей (и, как ни странно, влияет на некоторые браузеры чаще, чем на другие).
Мы видим эту проблему широко, возможно, около 1-2% нашего сайта с высоким трафиком. Я вижу это только в производстве, я не могу воспроизвести его в процессе разработки вообще.
Я вижу это в браузерах IE 11 и Edge больше всего (вы заметите, что Rails 4.1 был выпущен до IE 11 и Edge), но также и в Chrome на Android и иногда на мобильных Safari.
Наши заголовки Cache-control установлены следующим образом:
Cache-Control: max-age=0, private, must-revalidate
1 ответ
Это было идентифицировано и исправлено. Заголовки управления кэшем не были установлены в нашем приложении Rails 4.1, что привело к заголовкам по умолчанию
Cache-Control: max-age=0, private, must-revalidate
Этот заголовок недостаточно силен, чтобы браузеры не кэшировали. Таким образом, форма входа в систему и токен JSON кэшировались клиентским браузером, в частности мобильными клиентами, и возвращали сессионные идентификаторы с истекшим сроком действия.
Чинить:
Установить контроль кеша и заголовок прагмы, как таковой
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
а также
Pragma: no-cache
В рельсах, добавьте это в ваш application_controller.rb:
before_action :set_cache_headers
def set_cache_headers
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
end
Должно ли оно быть глобальным для каждого действия в вашем приложении? Это зависит от вас, но вы определенно захотите сделать это на любом контроллере, который отображает форму, особенно в форме входа в систему, или на любой странице, которая отображает маркер JSON, срок действия которого может истечь. Так что в современных приложениях короткий ответ - да.
Если вы явно хотите сохранить в кэше ответы вашего приложения Rails, вам нужно выяснить, как явно истечь эти токены CSRF и JSON, если они встроены.
Обратите внимание, что симптом проявляется на незначительных уровнях возникновения в основном на мобильных клиентах.