Как работает защита 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">

и когда я предоставляю свой логин, я вхожу в систему. Это означает, что токен не имеет никакого влияния. где я ошибаюсь?


Снайперская охота

  1. Версия Symfony 2.5.2
  2. Система зарегистрировала меня, когда я установил вручную переменную сеанса, "зарегистрированную" в true. Это происходит после чтения из базы данных и сравнения паролей.
  3. Форма 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>
    
  4. Да! я сделал

  5. Фактически, о чем я спорил все это время, я сделал процесс входа в систему родным способом, сформировал, прочитал данные с помощью JS, отправил запрос POST на контроллер, контроллер проверяет ввод и устанавливает сеанс.

  6. Нет, все сделано вручную

  7. На самом деле это первый раз, когда я использую security.yml, я просто удалил некоторые части, которые я считаю бесполезными для этой темы

  8. нет..

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 не достигается даже при обычном входе в систему.

Итак, теперь моя любимая часть. Снайперская охота. По сути, я сделал ряд предположений при чтении вопроса. Необходимо определить, какие предположения были неверными, задавая ряд базовых вопросов.

  1. Какую версию Symfony 2 вы используете. Я предполагаю, по крайней мере, S2.1.

  2. Как вы узнали, что система зарегистрировала вас? Используете ли вы панель инструментов отладки, и она показывает, что вы прошли проверку подлинности? Что происходит, когда вы пытаетесь войти с неверным паролем?

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

  4. Вы действительно добавили оператор die в vendor/symfony/symfony/src/Symfony/Component/Form/Csrf/CsrfProvider/DefaultCsrfProvider.php? Вы сохранили файл после редактирования?

  5. Вы на самом деле используете стандартный процесс form_login, верно? У вас нет кода, который, например, проверяет пароль пользователя?

  6. Вы используете какие-либо другие пакеты, например, FOSUserBundle?

  7. Файл security.yml в вашем вопросе действительно ваш настоящий файл? Вы не "очистили" после копирования?

  8. Вы проверили свое приложение в 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 для входа в систему брандмауэр. По моему опыту, отсутствие брандмауэра входа в систему в том же контексте, что и в защищенной области, не позволяет полностью получить доступ к контексту безопасности из вашего контроллера входа.

Другие вопросы по тегам