• Блог
  • [FormIt] Хук проверки токена

Приветствую всех в новом году! А православных поздравляю с Рождеством Христовым! В этой статье я покажу как с помощью библиотеки modHelpers защитить форму от CSRF атаки при использовании дополнения FormIt. Механизм защиты сайта был подробно описан в этой статье. Рекомендую с ней ознакомиться.

Мы знаем, что подключить свою логику к FormIt можно через хуки. Хук — это сниппет. Поэтому создаём сниппет и даем ему название «csrf». Он содержит всего несколько строчек:

if (request()->checkCsrfToken('post') === false) {
    // Выставляем плейсхолдер ошибки
    $hook->addError('csrf','Ошибка! Указан некорректный токен.');
    return false;
}
return true;

Он срабатывает только для формы, переданной POST методом. Теперь нужно создать форму. Для демонстрации возьмём такую простенькую:

<!-- Плейсхолдер ошибки -->
<div class="error">[[!+fi.error.csrf]]</div>

<form method="post" class="form">
    {csrf_field()}
    <div class="form-group">
        <label for="name">Имя:</label>
        <input type="text" name="name" id="name" value="[[!+fi.name]]" />
    </div>
    <div class="form-group">
        <label for="email">Email:</label>
        <input type="email" name="email" id="email" value="[[!+fi.email]]" />
    </div>
    <div class="form-buttons">
        <input type="submit" class="btn btn-default" value="Отправить" />
    </div>
</form>

У формы должно быть скрытое полей с токеном. Его можно вставить с помощью функции csrf_field(). Теперь форма готова к защите. Осталось вызвать сниппет FormIt с нашим хуком перед формой. Хуки срабатывают в порядке подключения. Поэтому указать его нужно самым первым.

[[!FormIt?
   &hooks=`csrf,email`
   ...
]]

В результате, при обработке запроса формы сниппет FormIt в первую очередь проверит токен. Если он не совпадёт с токеном пользователя или вообще отсутствует, то FormIt вернёт ошибку, и форма обрабатываться не будет.

Такая защита, кроме того, поможет оградить форму от большинства stateless (не использующих сессию) роботов и спамеров.

0   8222

Комментарии ()

  1. Николай Савин 14 ноября 2018 # 0
    Вставлю свои пять копеек (специально даже зарегистрировался).
    Что нужно знать и понимать.
    1. Очевидное. Должен быть установлен компонент modHelper
    2. Менее очевидно, я и сам носом ткнулся и видел что ребята страдают — в pdoTools обязательно должно быть включена работа с php в разделе с Fenom.
    3. В примере Сергея небольшая ошибка вот в этой строке
    $hook->addError('csrf','Ошибка! Указан некорректный токен.');
    
    Дело в том, что в первом параметре нужно обязательно указывать имя поля с CSRF токеном, для возвращения ошибки. А имя поля у нас не csrf, а csrf_token соответственно и строка должна быть такая
    $hook->addError('csrf_token','Ошибка! Указан некорректный токен.');
    
    Сразу оговорюсь — данная поправка актуальна для работы с ajaxForm. Если у вас чистый FormIt там вы можете указать для ошибки любую строку.
    Как работает FormIt
    Вы возвращаете ошибку в плейсхолдер, имя которого указываете в первом параметре строки
    $hook->addError('csrf','Ошибка! Указан некорректный токен.');
    
    Можно этот плейсходер хоть Васькой назвать и вызвать его в своей форме
    <div class=error> +fi.error.csrf  </div>
    
    а вот связка ajaxForm + formIt работает уже по другому.
    Здесь плейсхолдеры на странице не выводятся, они вообще не используются. Вместо них у нас есть всплывающие уведомления. Причем они показываются ТОЛЬКО в том случае, если имя уведомления соответствует имеющемуся в форме полю с аналогичным именем.

    Таким образом чтобы ajaxForm показал нам ошибку и прекратил выполнение отправки — мы должны вернуть ошибку, содержащую имя поля с csrf токеном.

    Если имя ошибки не соотвествует имени поля мы не только не увидим ошибки, но и отправим заявку на почту, даже если проверка на токен не прошла
    1. Сергей Шлоков 14 ноября 2018 # 0
      Вставлю свои пять копеек (специально даже зарегистрировался).
      Ну и правильно. Чем больше мнений, тем лучше.:q

      Отвечу по пунктам.
      1. В самом начале статьи я про modHelpers сказал. Ибо проверкой занимается именно она.
      2. Статья для продвинутых пользователей. «Мы знаем, что подключить свою логику к FormIt можно через хуки.» как бы намекает на это. Поэтому не разжевывал про pdoTools, так как статья не про это.
      3. Ошибкой это можно было бы назвать, если бы статья была написана про AjaxForm. Я про него не упоминал и писал для обычного FormIt. Просто целью статьи было не рассказать про работу FormIt или AjaxForm, а продемонстрировать как подключить хук проверки токена. Поэтому никакой ошибки нет, просто статья немного про другое. И, кстати, код совершенно рабочий.

      Из твоего комментария я могу сделать вывод, что у тебя FormIt в голове уже прочно связан с AjaxForm и ты уже на автомате читая про FormIt представляешь себе AjaxForm.:)

      П.С. Спасибо за комментарий. Возможно новичкам пригодится.
      1. Сергей Шлоков 14 ноября 2018 # 0
        Если имя ошибки не соотвествует имени поля мы не только не увидим ошибки, но и отправим заявку на почту, даже если проверка на токен не прошла
        По поводу этого не уверен, но проверять не хочется. Поверю на слово.;)
        1. Николай Савин 14 ноября 2018 # 0
          Скорее всего отправка не произойдет. Но ajaxForm success true все равно пришет и покажет соответствующее уведомление. Проверял.
      2. Сергей 26 июля 2019 # 0
        Добрый день!
        На сколько это актуально и на сколько защитит?
        Я уже не знаю как бороться со спамом, прилетает сразу по 4 письма, практически ежедневно.
        Сделал все как в инструкции, но проблему спама это вообще не как не решило.
        В режиме инкогнито почему-то так-же получается токен, так и должно быть?
        Есть по истине действенные решения, кроме установки капчи от google?
        Уже что только не пробовал сделать:
        1. Скрытое поле
        2. Капча, стандартная
        3. В ручную написанная капча
        4. Ваш метод, вроде все верно сделал.

        Уже просто нет сил бороться со всех этой фигней.
        1. Сергей Шлоков 26 июля 2019 # 0
          Данный способ защиты не предназначен для защиты от спама. От него он может помочь в одном единственном случае, если спам-робот не имеет сессии.

          В режиме инкогнито почему-то так-же получается токен, так и должно быть?
          Конечно. Если есть сессия, будет и токен. Но в этом случае он не будет иметь значения.

        Вы должны авторизоваться, чтобы оставлять комментарии.

        Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.