Безопасный FormIt
В позапрошлом году, когда я делал себе форму обратной связи с помощью дополнения 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, ...` ]]
Заключение
Может есть уже готовые решения, но я их не нашёл. Да и самому было интересно повелосипедить.
П.С. Не сразу решился про это написать, чтобы не создавать ненужных проблем от всяких школьников-мегахакеров. Но в конце концов решил, что профита от этих знаний больше — предупреждён, значит вооружён.
Комментарии ()
Вы должны авторизоваться, чтобы оставлять комментарии.
MODX Revolution 2.7.0-pl
1. Создал сниппет myAlphaNum
2. Создал сниппет myNoModxTags
3. вывод сниппета FormIt:
Если все поля заполнить корректно, а в поле «сообщения (message)» ввести:
AjaxForm пишет:
то есть выдает сообщение из:
на почту приходит:
Если В поле «имя» ввести, например: «Саша/», то выдает сообщение из:
Подскажи, что не так делаю. и как сделать правильно?
Заранее, благодарю!
Cовет. Добавь валидатор stripTags для поля message.
Ничего не выводится в журнале, если плейсхолдер существующий, например если ввести так:
а в письме, где должен быть текст сообщения, отображается pagetitle ресурса обратной связи.
Если указать:
то в журнале выводятся две одинаковых ошибки:
такие ошибки выводились и без указания в сниппете myNoModxTags
Код вызова сниппета myNoModxTags такой:
Добавил валидатор stripTags но это не помогает, все то же самое
Что-то вместо двоеточия перед :tripTags смайлик (кланяющийся) отображается в последнем блоке code в настоящем сообщении!?
Заинтересовал другой подход, но поскольку не очень силен в php и недавно познакомился с MODX, не совсем понятно как это реализовать. Если не затруднит, можешь привести в той статье пример реализации с плагином и с использованием компонента Middlewares. Сейчас в той статье задам этот вопрос.
Заранее, благодарен!
Его не нужно указывать в параметре customValidators. Он встроенный.
Если кроме формы обратной связи нет ввода пользовательских данных, то можно обойтись валидатором, т.е. без фильтрации всех входящих данных. В том же myNoModxTags заменять скобки на коды.
В данном случае не нужен myNoModxTag, который проверяет введённое сообщение и выдаёт ошибку, если находит скобки. Фильтр просто преобразует скобки на коды.
Fenom использую… только вывод сниппета у меня был не на Fenom.
Сейчас переписал его на Fenom и все заработало.
Подскажи, если реализовать другой подход и как ты рекомендовал там создать плагин на событие OnHandleRequest и приоритетом "-1000", то метод фильтрации, описанный в настоящей статье, будет уже неактуальный. Или можно сделать и это и то?
Использую плагины, где применяются $_GET и $_REQUEST, фильтрую я их там по мере моих знаний, но доп. фильтрация я думаю не помешает… возможно в дальнейшем будут плагины или еще что-то с $_GET, $_POST, $_REQUEST и $_COOKIE
Хотя в настоящей статье описана не фильтрация, а валидация формы, поэтому, думаю, если использовать только фильтрацию всех $_GET, $_POST, $_REQUEST и $_COOKIE и не применять валидацию формы, то форма будет отправляться, просто квадратные скобки будут вырезаться. А с валидацией формы, форма отправлена не будет и будет выдаваться сообщение «В форме содержатся ошибки!». Поэтому можно использовать два этих способа одновременно.
Правильно я понимаю?