Как работает защита Symfony2 CRSF?
Я пытаюсь протестировать систему защиты CRSF от Symfony2, большое им спасибо.
мой шаблон security.yml:(я изменил шаблон по умолчанию.)
security:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/demo/secured/login$
security: false
secured_area:
pattern: ^/demo/secured/
form_login:
check_path: _security_check
login_path: _demo_login
csrf_provider: form.csrf_provider
logout:
path: _demo_logout
target: _demo
#anonymous: ~
#http_basic:
# realm: "Secured Demo Area"
access_control:
#- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
В моей форме:
<input type="hidden" name="_csrf_token" value="{{ csrf_token("authenticate") }}">
Это создает что-то вроде этого:
<input type="hidden" name="_csrf_token" value="cKzXBHRDX_sHuT4qt9TAJIwgRvtRMtPnFDtitrSZDuw">
Я не знаю, как symfony обрабатывает проверки с помощью токена, но перед отправкой своего логина я изменил значение токена вручную, используя firebug, чтобы это выглядело так:
<input type="hidden" name="_csrf_token" value="MODIFIEDcKzXBHRDX_sHuT4qt9TAJIwgRvtRMtPnFDtitrSZDuw">
и когда я предоставляю свой логин, я вхожу в систему. Это означает, что токен не имеет никакого влияния. где я ошибаюсь?
Снайперская охота
- Версия Symfony 2.5.2
- Система зарегистрировала меня, когда я установил вручную переменную сеанса, "зарегистрированную" в true. Это происходит после чтения из базы данных и сравнения паролей.
Форма HTML!
<form id="Loginform" onsubmit="OrganicLogin();return false;"> <input type="hidden" name="_csrf_token" value="{{ csrf_token("authenticate") }}"> <div id="Loginresponse" style="display:none;"></div> <div class="form-group" style="overflow:hidden;"> <label style="margin-top:10px;" for="inputUsername" class="col-lg-2 control-label">Username</label> <div class="col-lg-10"> <input type="text" class="form-control" id="inputUsername" placeholder="Username" style="width:215px;float:right;"> </div> </div> <div class="form-group" style="overflow:hidden;" > <label style="margin-top:10px;" for="inputPassword" class="col-lg-2 control-label">Password</label> <div class="col-lg-10"> <input type="password" class="form-control" id="inputPassword" placeholder="Password" style="width:215px;float:right;"> </div> </div> <div class="form-group" style="overflow:hidden;text-align:center;" > <button type="submit" class="btn btn-primary btn-block" id="submitButton">Access</button> </div></form>
Да! я сделал
Фактически, о чем я спорил все это время, я сделал процесс входа в систему родным способом, сформировал, прочитал данные с помощью JS, отправил запрос POST на контроллер, контроллер проверяет ввод и устанавливает сеанс.
Нет, все сделано вручную
На самом деле это первый раз, когда я использую security.yml, я просто удалил некоторые части, которые я считаю бесполезными для этой темы
нет..
2 ответа
Я догадываюсь, что ваш измененный токен не публикуется. Вставьте кубик в:
namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
class DefaultCsrfProvider implements CsrfProviderInterface
{
public function isCsrfTokenValid($intention, $token)
{
die('csrf token ' . $intention . ' ' . $token);
return $token === $this->generateCsrfToken($intention);
}
Если кубик достигнут, то вы знаете, что с вашей конфигурацией все в порядке и, конечно, вы можете увидеть фактический токен, который был отправлен.
Излишне говорить, что вы также должны очистить кэш.
================================================== =====
Обновление 1 - После многих комментариев мы определили, что die() не вызывается. Прогресс.
К сожалению, нам все еще нужно проверить, как именно постер настроил свою систему.
Следующий шаг - войдите в систему, не корректируя токен csrf через firebug, и убедитесь, что оператор die достигнут.
Сообщать так или иначе.
Само собой разумеется (но я все равно это скажу), убедитесь, что вы вышли из системы, прежде чем пытаться войти снова.
================================================== ======
Обновление 2 - оператор die не достигается даже при обычном входе в систему.
Итак, теперь моя любимая часть. Снайперская охота. По сути, я сделал ряд предположений при чтении вопроса. Необходимо определить, какие предположения были неверными, задавая ряд базовых вопросов.
Какую версию Symfony 2 вы используете. Я предполагаю, по крайней мере, S2.1.
Как вы узнали, что система зарегистрировала вас? Используете ли вы панель инструментов отладки, и она показывает, что вы прошли проверку подлинности? Что происходит, когда вы пытаетесь войти с неверным паролем?
Используйте функцию просмотра исходного кода вашего браузера и скопируйте сгенерированную форму в свой вопрос. В частности, я хочу видеть атрибут действия, но я также хочу видеть элементы ввода.
Вы действительно добавили оператор die в vendor/symfony/symfony/src/Symfony/Component/Form/Csrf/CsrfProvider/DefaultCsrfProvider.php? Вы сохранили файл после редактирования?
Вы на самом деле используете стандартный процесс form_login, верно? У вас нет кода, который, например, проверяет пароль пользователя?
Вы используете какие-либо другие пакеты, например, FOSUserBundle?
Файл security.yml в вашем вопросе действительно ваш настоящий файл? Вы не "очистили" после копирования?
Вы проверили свое приложение в github? Если да, то можете ли вы предоставить ссылку? Просмотр всего приложения, вероятно, будет самым быстрым способом прояснить ситуацию.
Этого должно быть достаточно на данный момент. Обновите ваш вопрос вашими ответами.
================================================== =======================
Обновление 3 - сюжет утолщается
Как я уже писал в приведенных выше вопросах, мы обнаруживаем, что сама базовая система входа в систему не настроена должным образом. Панель инструментов отладки показала, что пользователь не аутентифицирован. Больше прогресса! Как это часто бывает, симптомы маскировали реальную проблему.
Система безопасности является, пожалуй, самым сложным компонентом в Symfony 2, с которым типичные разработчики должны взаимодействовать. При настройке легко запутаться и устранить неполадки. Одна крошечная опечатка может растопить вещи. Для разработчика также очень важно иметь представление о том, как реализована безопасность. Если, конечно, вы не такая большая компания, как Target или Home Depot.
Я предлагаю создать свежий проект Symfony 2 с помощью composer. Затем перейдите по http://symfony.com/doc/current/book/security.html и настройте систему безопасности. Пусть это будет своего рода справочное приложение для понимания безопасности.
Я подозреваю, что к концу процесса вы поймете проблему и сможете применить решение к существующему приложению. В качестве бонуса у вас будет что-то, к чему вы можете обратиться для решения будущих проблем.
================================================== ================
Обновление 4 - захватывающее заключение
Итак, теперь мы обнаруживаем, что используется нестандартная и наивная система входа в систему.
Я бы все же предложил начать с нового проекта и начать работать с Symfony 2. После этого вы можете настроить форму входа в систему, чтобы использовать javascript, если вы действительно этого хотите.
Если вы действительно действительно хотите использовать свою собственную систему, тогда начните здесь: Ручная аутентификация пользователя
Но вы бы выбросили одну из главных сильных сторон Symfony без особой причины.
Предполагается, что Symfony генерирует токен CSRF, который он автоматически вставляет в форму. Он сохраняет этот токен в текущем сеансе. Когда форма отправлена, она сравнивает отправленный токен со значением, сохраненным в сеансе. Что касается вашего конкретного случая, это просто звучит так, как будто CSRF на самом деле не включен, и это может быть связано с тем, что контексты безопасности не разделяются между брандмауэром защищенной области, в котором включена функция CSRF, и брандмауэром входа в систему, который этого не делает.
Попробуйте удалить этот бит в вашем security.yml:
login:
pattern: ^/demo/secured/login$
security: false
И вместо этого, перемещая его в контекст secured_area и используя элементы управления доступом для предоставления доступа:
...
form_login:
check_path: _security_check
login_path: login
...
access_control:
- { path: ^/demo/secured/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
В качестве альтернативы, вы можете попробовать добавить context: secured_area
для входа в систему брандмауэр. По моему опыту, отсутствие брандмауэра входа в систему в том же контексте, что и в защищенной области, не позволяет полностью получить доступ к контексту безопасности из вашего контроллера входа.