jcmax
@jcmax
Супер Пользователь

Нужно ли фильтровать глобальные переменные в PHP?

Добрый день, пилю здесь ради интереса и само развития сms (домашнего разлива) со всеми велосипедами.

Есть куча вопросов по образу или культуре программирования.

Первый например нужно ли каждый раз в каждом методе проверять параметры входящих переменных, Например есть в Model
CLASS::MODEL

function adduser(string $name, string $password): bool {
// нужно ли тут проверять пустые ли переменные???

return true;
}


и например Controller
CLASS::CONTROLLER
function getUserParams() {

   // Получаем данные из _POST username и password и запускаем модель
   adduser($name, $password);
}


Другой вопрос интересует есть класс фильтр например который фильтрует входные данные _GET, _POST
Нужно ли фильтровать данные из _COOKIE, _HEADER, _SERVER,

к примеру
?query=<script>alert('о, привет!'); </script>
выдает модальное окошко если запустить $_SERVER['[REQUEST_URI']
  • Вопрос задан
  • 168 просмотров
Пригласить эксперта
Ответы на вопрос 3
index0h
@index0h
PHP, Golang. https://github.com/index0h
нужно ли тут проверять пустые ли переменные???

Этот подход считается довольно геморным, но он колоссально экономит время при отладке. Так что да, это стоит делать.

Что касается глобальных переменных - лучше их не использовать.
Ответ написан
@alexalexes
Можно ограничится проверками только тех данных, которые приняты от клиентской части системы и могут быть заведомо изменены пользователем так, чтобы вызвать неожиданное поведение в серверной части.
Если один метод генерирует данные для другого метода на стороне сервера, и они без проверок не выходят транзитом через клиентскую часть приложения или через другую часть приложения, где есть канал связи (точка отказа), то можно не делать проверки в каждом методе. Важно соблюдать условие, что если какой-то элемент данных пришел от пользователя и на входе в серверной части его проверили один раз (может быть даже заэкранировали), то внутри системы этим элементом данных уже можно спокойно пользоваться.
Нужно ли фильтровать данные из _COOKIE, _HEADER, _SERVER,
к примеру
?query=
выдает модальное окошко если запустить $_SERVER['[REQUEST_URI']

Вы ничего не запускаете, вы просто отдаете ответ браузеру (делаете эхо) от того, что пришло в части строки адреса, где содержатся get-параметры.
Браузер, не получив внятного описания, что ему ответили html содержимым, пытается обернуть ответ в нечто валидное по html нотации:
<html>
<body>
?query=<script>alert('о, привет!'); </script>
</body>
</html>

Далее, браузер пытается воспроизвести это. Строит DOM-дерево, находит тег script, пытается выполнить у себя JS-код. На этом можно обжечься когда выводите сведения в textarea.
$unsafe_string_for_html = "<script>alert('о, привет!'); </script>";
echo '<textarea>'.$unsafe_string_for_html.'</textarea>';

Чтобы такое не происходило, перед выводом небезопасных для html разметки элемента данных, нужно над ним провести экранирование.
$unsafe_string_for_html = "<script>alert('о, привет!'); </script>";
$safe_string_for_html = htmlspecialchars($unsafe_string_for_html);
echo '<textarea>'.$safe_string_for_html.'</textarea>';

Можно провести экранирование и в момент получения данных, тогда при отдаче браузеру можно будет быть уверенным, что это не выполняемые инструкции, а текстовые данные с точки зрения html. Однако, когда сохраняете в базу эти данные или делаете их обработку, нужно иметь ввиду что они прошли экранирование по html и содержание некоторых символов будет немного другое чем это проецируется в браузере.
Ответ написан
ipatiev
@ipatiev Куратор тега PHP
Потомок старинного рода Ипатьевых-Колотитьевых
Как и многие начинающие, вы путаете фильтрацию (<script>) и валидацию (нужно ли тут проверять пустые ли переменные???), при том что это совершенно разные, никак не связанные между собой задачи.

И решают их тоже по-разному.

Фильтрация:
1. Делается строго в момент использования данных
2. Не имеет ни малейшего отношения к источнику данных.
Например, исходя из правила №1, как выше правильно написал alexalexes, при выводе любых данных в контекст HTML, необходимо их обрабатывать htmlspecialchars.
Исходя из правила №2 (фильтруются любые данные, вне зависимости от источника) становится понятным, что ваш "класс фильтр например который фильтрует входные данные" - это Очень Плохая Идея. Мало того что он никак не фильтрует те данные, которые вы не сочли "входящими" (при том что любая кавычка или знак "меньше" в самых супер-доверенных данных поломает вам верстку не хуже злобного хакера), но главное - на момент централизованной фильтрации вы просто не знаете, как данные будут использоваться. А вдруг это будет не вывод в HTML? А вдруг это XML c из Яндекс.Маркета и ваша "фильтрация" превратит его в тыкву?

Вывод: фильтровать надо любые переменные, а не только "глобальные", причём не заранее, а строго в момент использования. И не всегда под одну гребёнку, а в зависимости от контекста.
И в этом случае ваш пример с REQUEST_URI не сработает - он зафильтруется при выводе.

Валидация:
Валидация - это проверка данных на соответствие заданным параметрам. Это может быть не только пустота, но и размер, соответствие формату, налитчие уже таких данных в БД - миллион разных проверок.
Валидация пишется для каждой переменной отдельно.

Где её делать - спорный вопрос.

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

При этом по-хорошему, в контроллере тоже необходимо делать валидацию, специфичную именно для входящих данных.
Например, проверить, что в запросе пришли все требуемые поля, элементы name и password присутствуют во входящем массиве. В этом случае можно в какой-то мере говорить о валидации "глобальных переменных" (хотя на самом деле вы имеете в виду входящие данные)
Также можно проверять некоторые данные на соответствие формату. Нет смысла дергать модель, если мы заранее знаем, что данные не те. Например, вместо id новости в запросе пришло "админ - дурак".
Или взять ваш пример с query: если содержимое этой переменной должно соответствовать какому-то строгому формату, который не допускает наличие символов < и >, то вы можете проверить его на соответствие формату, и вернуть 400 ошибку.
Но опять же - никакой централизованной проверки здесь придумать нельзя. У всех входящих переменных свой собственный формат: у ид из бд - числовой, у емейла - емейл, и так далее. Поэтому проверять надо каждое значение по отдельности. Но все эти проверки в общем не являются обязательными. В отличие от фильтрации.

То есть можно выделить два типа валидации - валидацию входящих данных (в контроллере), и валидацию на соответствие данных определённому формату (в модели).

Учитывая, что эти два вида валидации зачастую пересекаются, обычно никто не заморачивается, и всю валидацию делают в контроллере. Что не совсем правильно с точки зрения архитектуры (модель может быть вызвана не только из контроллера), но зато проще в реализации.

Главное, что важно помнить про валидацию - она не должна быть молчаливой. Если данные не прошли валидацию, это должно вызывать внятную ошибку. В этом случае это действительно поможет при отладке. А если "валидация" молча коверкает данные, то это наоборот - фантастически затруднит отладку
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы