Как работает защита 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. Система зарегистрировала меня, когда я вручную установил для переменной сеанса «logged» значение 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. no ..


person Aysennoussi    schedule 10.09.2014    source источник
comment
мой адрес для входа /login   -  person Aysennoussi    schedule 10.09.2014
comment
Вы можете протестировать ist с помощью метода cURL и POST (просто не устанавливайте поле _csrf_token) и распечатать вывод.   -  person Lkopo    schedule 10.09.2014
comment
Нужно ли мне что-то писать в моем контроллере?   -  person Aysennoussi    schedule 10.09.2014
comment
Для этого не используйте внешний скрипт (если вы имеете в виду тест cURL).   -  person Lkopo    schedule 10.09.2014
comment
Я не имел в виду тест cUrl, ваш первый комментарий означает, что просто установка csrf_token может обойти защиту? Пожалуйста, если вы знаете, скажите мне, как symfony сравнивает $_POST['csrf_token'] и другой элемент.. Я запутался..   -  person Aysennoussi    schedule 10.09.2014
comment
Я до сих пор не понимаю, почему это работает, когда я меняю ввод вручную, обычно это не должно работать, верно?   -  person Aysennoussi    schedule 10.09.2014
comment
См. комментарий @Cerad.   -  person Lkopo    schedule 10.09.2014


Ответы (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 без особой причины.

person Cerad    schedule 10.09.2014
comment
На самом деле это мой первоначальный вопрос: нужно ли мне что-то добавить в мой контроллер, чтобы защита работала? - person Aysennoussi; 10.09.2014
comment
Если вам действительно нужны уродливые подробности аутентификации пользователей, взгляните на: symfony. com/doc/current/cookbook/security/. Но это не для слабонервных. Поверьте мне, когда я говорю, что в конечном итоге вызывается isCsrfTokenValid(). - person Cerad; 10.09.2014
comment
Спасибо ! Это интересно. Вы сказали что-то хитрое, о чем я не знаю. Контроллеры никогда не попадают во время проверки входа в систему. Все сделано со слушателями Мой процесс входа в систему находится внутри контроллера! мне нужно что-то изменить? - person Aysennoussi; 10.09.2014
comment
Ваш login_path использует контроллер для представления формы входа. Но когда вы отправляете форму, она переходит в check_path. Это получает прослушиватель и выполняет фактическую аутентификацию пользователя. Еще раз, если вы следовали книге, вам больше ничего не нужно делать. - person Cerad; 10.09.2014
comment
Я следил за книгой только для части CSRF, но часть входа в систему была сделана нативным образом, все было внутри контроллера, и контроллер вызывался напрямую. Я думаю, именно поэтому CSRF не работал. Как вы думаете? - person Aysennoussi; 10.09.2014
comment
Я думаю, вам следует добавить оператор die, а затем сообщить, достигнут он или нет. Если по какой-то причине вы не хотите этого делать, я уверен, что есть много других людей, которые могут помочь. И еще раз, ваш контроллер login_path не имеет ничего общего с проверкой csrf. - person Cerad; 10.09.2014
comment
Я сделаю это ! Я просто хочу удостовериться, что делаю это на практике. - person Aysennoussi; 10.09.2014
comment
В порядке. Я обновил ответ. Следующий шаг — выполнить обычный вход в систему и убедиться, что матрица достигнута. - person Cerad; 10.09.2014
comment
На самом деле это не было достигнуто без моего изменения csrf! - person Aysennoussi; 10.09.2014
comment
У меня такое чувство, что я делаю процедуру входа в систему неправильным способом symfony2. панель отладки Symfony говорит мне, что я не аутентифицирован - person Aysennoussi; 10.09.2014
comment
Сделаем это Бро! Я тоже в восторге! Я отвечу на все ваши предположения и отредактирую свой вопрос, чтобы опубликовать ответы в удобочитаемом формате. - person Aysennoussi; 10.09.2014
comment
Спасибо вам большое за ваше время! - person Aysennoussi; 10.09.2014

Предполагается, что это работает следующим образом: Symfony генерирует токен CSRF, который автоматически вставляется в форму. Он сохраняет этот токен в текущем сеансе. Когда форма отправляется, она сравнивает отправленный токен со значением, хранящимся в сеансе. Что касается вашего конкретного случая, это просто звучит так, как будто CSRF на самом деле не включен, и это может быть связано с тем, что контексты безопасности не используются совместно между брандмауэром защищенной области, в котором включен CSRF, и брандмауэром входа в систему, который этого не делает.

Попробуйте удалить этот бит в файле security.yml:

login:
    pattern:  ^/demo/secured/login$
    security: false

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

person Leo Bedrosian    schedule 11.09.2014