Где Rails 4 хранит токен аутентификации для защиты от CSRF?

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

  protect_from_forgery :only => [:foo, :bar]

Когда я загружаю URL-адреса, соответствующие foo и bar, и просматриваю HTML, я не вижу никаких скрытых полей ввода или метатегов, содержащих токены безопасности, как описано здесь.

Однако во время тестирования я заметил, что CSRF не эффективен против этих страниц, хотя он эффективен против других незащищенных страниц того же приложения.

Так где же Rails 4 хранит токен безопасности, который используется для проверки того, что запрос пришел с исходной страницы?

Обратите внимание, что я уже прочитал Руководство по безопасности Ruby On Rails и раздел protect_from_forgery, это говорит

Это будет автоматически включать токен безопасности во все формы и запросы Ajax, сгенерированные Rails. Если маркер безопасности не соответствует ожидаемому, сеанс будет сброшен.

Проблема в том, что токен безопасности отсутствует в формах на страницах с включенной защитой CSRF, хотя CSRF действительно неэффективен против них.


Обратите внимание: этот код взят из проекта класса, в котором одной из целей является выполнение атаки clickjacking для обхода проекта CSRF. Вопрос, который я здесь задаю, ортогонален цели задания.

Мне просто любопытно, как именно Rails делает CSRF.

После выполнения rails server напрямую соответствующий URL-адрес, для которого я не могу найти токен безопасности, — http://localhost:3000/protected_transfer.


person merlin2011    schedule 05.05.2014    source источник


Ответы (1)


Токен CSRF хранится в сеансе пользователя (который по умолчанию находится в файле cookie в Rails; зашифрованный файл cookie в Rails 4). Он дополнительно записывается на страницу как в виде тега <meta> (для использования библиотеками Javascript) с помощью вспомогательного метода csrf_meta_tags, так и в скрытом поле в любых формах, сгенерированных form_tag или form_for на странице.

Глядя на этот проект, причина, по которой токен CSRF не появляется, заключается в том, что HTML написан с буквальным тегом <form>, а не с вспомогательным form_for, который включает токен CSRF. Кроме того, в макете отсутствует помощник csrf_meta_tags, поэтому метатег не записывается.

Форма жестко закодирована для публикации в <form action="post_transfer" method="post">, которая не должна быть защищена защитой CSRF, поэтому эта форма должна поддерживать CSRF, даже если представление помечено как protect_from_forgery. Метод protected_post_transfer вряд ли примет даже законные запросы, поскольку токен аутентификации никогда не отправляется.

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

person Chris Heald    schedule 05.05.2014
comment
Спасибо, что посмотрели код проекта. Удивительно, но он действительно принимает законные запросы, и теперь я ломаю голову, пытаясь понять, почему. - person merlin2011; 05.05.2014
comment
Он публикуется в post_transfer (действие формы жестко закодировано), а не в protected_post_transfer, поэтому на самом деле он должен быть уязвим для CSRF. Вы уверены, что это не так? - person Chris Heald; 05.05.2014
comment
Очень хороший улов! Похоже, инструкторы напортачили. Я укажу на protected_post_transfer и посмотрю, принимает ли он какие-либо запросы. - person merlin2011; 05.05.2014
comment
Как бы то ни было, вот почему form_for и помощники пути Rails хороши — они управляют всеми подобными вещами за вас, поэтому такие ошибки не возникают! - person Chris Heald; 05.05.2014
comment
Вы были абсолютно правы. Этот код не принимает законные запросы при нажатии protected_post_transfer. Это отвечает на вопрос, хотя и не так, как я ожидал. - person merlin2011; 05.05.2014
comment
FWIW, способ включить защиту — использовать помощник form_tag, например <%=form_tag protected_post_transfer_path do %> ... <% end %>, а не <form>...</form>. Если вы переключитесь на это, вы заметите, что скрытое поле, содержащее аутентификацию_токен, записано в HTML. - person Chris Heald; 05.05.2014