В позапрошлом году, когда я делал себе форму обратной связи с помощью дополнения FormIt, во время тестирования обнаружил интересную фичу (на самом деле потенциальную дыру) — в форме можно указывать теги MODX (чанки, сниппеты, поля). FormIt обрабатывает только HTML теги, а вот MODX теги он пропускает. И проявляется это при использовании хуков email и FormItAutoResponder (автоответчика). Покопавшись в документации и погуглив, я не нашёл базового решения данной проблемы для экранирования тегов MODX. Поэтому просто тупо поставил фильтр esc в чанке email шаблона. Он экранирует квадратные скобки и обратные кавычки. Данное решение меня устроило на 100% и я про это забыл.

Пару дней назад мне через форму обратной связи обратился человек с очень наивным вопросом — можно ли указывать в поле [[*content]] чанки? Вроде вопрос как вопрос. Но через некоторое время меня стало одолевать подозрение, что этот вопрос был с изюминкой. Я продублировал этот вопрос без фильтра и получил старую проблему. В принципе, меня это пугать не должно — фильтр esc отлично отрабатывает. Но появилось одно обстоятельство, о котором я тогда не подумал. Это шаблонизатор Fenom. Когда я разрабатывал форму, я им не пользовался. Но в дальнейшем я на него перешёл, а про форму, конечно, даже и думать забыл. А его-то теги не эскейпятся.

В очередной раз полез в документацию и убедился, что ничего нового по этому поводу там не появилось. Таким образом вся ответственность за обработку данных FormIt перекладывает на разработчика и никаких рекомендаций по этому поводу не даётся.

А проблема-то серьёзная. Если вдруг вы используете хук автоответчика и в шаблоне письма у вас есть тег поля формы (например, «Уважаемый [[+name]]!»), то пользователь может получить любую информацию о системе. Например, тот же префикс таблиц. И происходит этого из-за того, что пользовательские данные передаются в парсер без фильтрации через вызов метода getChunk().

Решений можно придумать несколько. Например, заменять скобки на соответствующие коды. Но я выбрал решение с пользовательским валидатором, который будет разрешать разрешённые и запрещать запрещенные символы. Ибо нефиг в форме обратной связи использовать лишнее. Для этого я создал пару сниппетов. Первый назвал alphaNum:

$result = (bool) preg_match_all('/^[0-9A-Za-zА-Яа-я_\-\s]+$/u', $value);
if (!$result) {
  $validator->addError($key,'Поле заполнено некорректно!');
}
return $result;

Теперь в поле «Имя» можно вводить только цифры, буквы и ещё несколько симоволов.

Для поля «Сообщение» я создал валидатор с паттерном /^[^\{\}\[\]]+$/, который просто запрещает вводить скобки для тегов MODX и Fenom.

Вообще, в FormIt есть встроенный валидатор regex. Но я не смог его заставить работать корректно. И мне кажется, что решение в виде отдельного валидатора выглядит несколько практичнее.

Дальше нужно вставить их в вызов FormIt:

[[!FormIt?
    ...
    &customValidators=`alphaNum,noModxTags`  // Нужно их подключить
    &validate=`name:required:minLength=^3^:alphaNum,
               message:required:noModxTags,
               ...` 
]]

Заключение

Может есть уже готовые решения, но я их не нашёл. Да и самому было интересно повелосипедить.

П.С. Не сразу решился про это написать, чтобы не создавать ненужных проблем от всяких школьников-мегахакеров. Но в конце концов решил, что профита от этих знаний больше — предупреждён, значит вооружён.

0   1701

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

  1. Дмитрий 31 января 2019, 00:07 # 0
    Сергей, что-то не работает, может я не так сделал.

    MODX Revolution 2.7.0-pl

    1. Создал сниппет myAlphaNum
    <?php
    $result = (bool) preg_match_all('/^[0-9A-Za-zА-Яа-я_\-\s]+$/u', $value);
    if (!$result) {
      $validator->addError($key,'Поле заполнено некорректно!');
    }
    return $result;

    2. Создал сниппет myNoModxTags
    <?php
    $result = (bool) preg_match_all('/^[^\{\}\[\]]+$/u', $value);
    if (!$result) {
      $validator->addError($key,'Поле заполнено некорректно!');
    }
    return $result;

    3. вывод сниппета FormIt:
    [[!AjaxForm@MyAjaxForm?
                &snippet=`FormIt`
                &form=`@FILE chunks/forms/contact_form.tpl`
                &hooks=`email,FormItSaveForm`
                &formName=`Форма со страницы контакты`			
                &formFields=`name,email,subject,message`			
                &fieldNames=`name==Имя,email==E-mail,subject==Тема вопроса,message==Текст сообщения`			
    			&customValidators=`myAlphaNum,myNoModxTags`
    
                    &validate=`
    				name:required:minLength=^3^:myAlphaNum,
    				email:email:required,
    				subject:required,
    				message:required:minLength=^6^:myNoModxTags
    				`
    			
                &validationErrorMessage=`Что-то пошло не так, проверьте правильность введенных данных!`			
                &successMessage=`Ваше сообщение успешно отправлено!`			
                &emailTo=`dfg****fdasd@*******.ru`
                &emailTpl=`@FILE chunks/email/contacts_email.tpl`
                &emailSubject=`Письмо со страницы контакты`
                &emailFromName=`От меня`
                &validationErrorMessage=`В форме содержатся ошибки!`
                &successMessage=`Форма успешно отправлена!`
                ]]

    Если все поля заполнить корректно, а в поле «сообщения (message)» ввести:
    [<b></b>[flag]<b></b>]
    AjaxForm пишет:
    Форма успешно отправлена!
    то есть выдает сообщение из:
    &successMessage=`Форма успешно отправлена!`
    на почту приходит:
    [[flag]]


    Если В поле «имя» ввести, например: «Саша/», то выдает сообщение из:
    &validationErrorMessage=`В форме содержатся ошибки!`

    Подскажи, что не так делаю. и как сделать правильно?

    Заранее, благодарю!
    1. Сергей Шлоков 31 января 2019, 08:31 # 0
      Попробуй в сниппете noModxTags в самом начале вставить
      $modx->log(1, $value);
      и посмотри, что выводится в журнале ошибок. Скорее всего у тебя скобки закодированы. Я же использую другой подход.

      Cовет. Добавь валидатор stripTags для поля message.
    2. Дмитрий 01 февраля 2019, 22:07 # 0
      Попробуй в сниппете noModxTags в самом начале вставить
      $modx->log(1, $value);
      и посмотри, что выводится в журнале ошибок. Скорее всего у тебя скобки закодированы...


      Ничего не выводится в журнале, если плейсхолдер существующий, например если ввести так:
      [<b></b>[*pagetitle]<b></b>]
      а в письме, где должен быть текст сообщения, отображается pagetitle ресурса обратной связи.

      Если указать:
      [<b></b>[flag]<b></b>]
      то в журнале выводятся две одинаковых ошибки:

      ...model/modx/modparser.class.php : 541) Could not find snippet with name flag.
      ...model/modx/modparser.class.php : 541) Could not find snippet with name flag.
      такие ошибки выводились и без указания в сниппете myNoModxTags
      $modx->log(1, $value);

      Код вызова сниппета myNoModxTags такой:
      <?php
      $modx->log(1, $value);
      $result = (bool) preg_match_all('/^[^\{\}\[\]]+$/u', $value);
      if (!$result) {
        $validator->addError($key,'Поле заполнено некорректно!');
      }
      return $result;

      Добавил валидатор stripTags но это не помогает, все то же самое
      &customValidators=`myAlphaNum,myNoModxTags,stripTags`
      
                  &validate=`
      		name:required:minLength=^3^:myAlphaNum,
      		email:email:required,
      		subject:required,
      		message:required:minLength=^6^:stripTags:myNoModxTags
      		`
      Что-то вместо двоеточия перед :tripTags смайлик (кланяющийся) отображается в последнем блоке code в настоящем сообщении!?

      Заинтересовал другой подход, но поскольку не очень силен в php и недавно познакомился с MODX, не совсем понятно как это реализовать. Если не затруднит, можешь привести в той статье пример реализации с плагином и с использованием компонента Middlewares. Сейчас в той статье задам этот вопрос.

      Заранее, благодарен!
      1. Сергей Шлоков 02 февраля 2019, 10:14 # 0
        Ничего не выводится в журнале
        А должно. Значит сниппет myNoModxTags не срабатывает.

        Добавил валидатор stripTags но это не помогает
        Его не нужно указывать в параметре customValidators. Он встроенный.

        Заинтересовал другой подход, но поскольку не очень силен в php и недавно познакомился с MODX
        Если кроме формы обратной связи нет ввода пользовательских данных, то можно обойтись валидатором, т.е. без фильтрации всех входящих данных. В том же myNoModxTags заменять скобки на коды.
        1. Сергей Шлоков 02 февраля 2019, 10:47 # 0
          Кстати, если ты не используешь Fenom, то достаточно указать фильтр esc в тегах в шаблоне письма.
          Уважаемый [[+name:esc]]!
          В данном случае не нужен myNoModxTag, который проверяет введённое сообщение и выдаёт ошибку, если находит скобки. Фильтр просто преобразует скобки на коды.
          1. Дмитрий 02 февраля 2019, 14:13 # 0
            Благодарю.
            Fenom использую… только вывод сниппета у меня был не на Fenom.
            Сейчас переписал его на Fenom и все заработало.

            Подскажи, если реализовать другой подход и как ты рекомендовал там создать плагин на событие OnHandleRequest и приоритетом "-1000", то метод фильтрации, описанный в настоящей статье, будет уже неактуальный. Или можно сделать и это и то?

            Если кроме формы обратной связи нет ввода пользовательских данных, то можно обойтись валидатором, т.е. без фильтрации всех входящих данных.

            Использую плагины, где применяются $_GET и $_REQUEST, фильтрую я их там по мере моих знаний, но доп. фильтрация я думаю не помешает… возможно в дальнейшем будут плагины или еще что-то с $_GET, $_POST, $_REQUEST и $_COOKIE
            1. Дмитрий 02 февраля 2019, 14:39 # 0
              Подскажи, если реализовать другой подход и как ты рекомендовал там создать плагин на событие OnHandleRequest и приоритетом "-1000", то метод фильтрации, описанный в настоящей статье, будет уже неактуальный. Или можно сделать и это и то?

              Хотя в настоящей статье описана не фильтрация, а валидация формы, поэтому, думаю, если использовать только фильтрацию всех $_GET, $_POST, $_REQUEST и $_COOKIE и не применять валидацию формы, то форма будет отправляться, просто квадратные скобки будут вырезаться. А с валидацией формы, форма отправлена не будет и будет выдаваться сообщение «В форме содержатся ошибки!». Поэтому можно использовать два этих способа одновременно.

              Правильно я понимаю?
              1. Сергей Шлоков 02 февраля 2019, 20:24 # 0
                Не совсем. Фильтр переведёт скобки в коды. Поэтому валидатор уже не найдёт скобки и пропустит форму.

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

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