Защита PHP кода: ограничение ввода, проверка данных и экранирование отображения.

12.12.2019
Сложность
9 мин.
2151

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

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

Главный  совет звучит так: «Не доверяйте никому» - по умолчанию любой пользователь вашего сайта является злоумышленником. Исходя из этого каждое сомнительное место в вашем коде нуждается в гарантированной защите.

Для того чтобы сохранить контроль над сценарием приложения, необходимо добавить дополнительные уровни защиты к вашему коду, проверять и ограничивать доступ внешних источников.

К внешним источникам можно отнести следующие пункты:

  • $_POST
  • $_GET
  • $_REQUEST
  • $_COOKIE
  • file_get_contents()
  • Базы данных
  • API-интерфейсы
  • Входные данные от клиентов
  • $argv
  • PHP://STDIN
  • PHP://input

Все приведенные выше источники являются ресурсами, которые могут злонамеренно использоваться для внедрения вредоносных данных в ваш код.

Ограничение входных данных.

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

Существует несколько типов ввода, которые необходимо учитывать при очистке. Наиболее распространенными являются HTML-формы, ввод с помощью запросов SQL и пользовательская информация.

Ввод через HTML

Представьте, что у вас есть блог, который позволяет комментировать посты, и какой-то случайный парень из Интернета, после прочтения вашего поста в блоге, решает набрать комментарий, включающий очень простой JavaScript код, что-то вроде команды window.location.href=’https://reklama.com’.

В результате каждый раз, когда кто-то (после того, как наш друг оставил свой cюрприз) нажимает на сообщение на нашей странице, он или она будет перенаправлен на определённую злоумышленником страницу.

Чтобы решить эту проблему, используйте команду PHP htmlentities() .

Эта функция экранирует все символы HTML в строке и делает ее безопасной.

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

Чтобы решить эту проблему, нам нужно научиться использовать ее аргументы.

Первым аргументом, который принимает эта функция, является строка, которую мы должны очистить.

Вторым аргументом является константа ENT_QUOTES, которая обязывает функцию кодировать одинарные кавычки.

И последний аргумент позволяет указать кодировку, которую вы используете в своем приложении.

Базовый пример будет выглядеть так:

echo htmlentities($string, ENT_QUOTES, 'UTF-8');

SQL-запросы

Иногда нам, как разработчикам, нужно строить запросы SQL в соответствии с тем, что шлёт нам пользователь.

Эти входные данные могут поступать из строки запроса (например:?user=1) или URI (например: user/1).

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

Например, подготовим строку с запросом для последующего обновления пароля:

$changePassword = sprintf(
    'UPDATE users set password = "%s" WHERE id = "%s"',
    $_POST['password'],
    $_GET['id'],
);

Что не так с этим кодом?

Не забывайте совет «не доверяйте никому».

Уровень защиты этого кода очень слабый, на самом деле он вообще отсутствует.

Что произойдет, если кто-то отправит HTTP-запрос в ваш PHP-скрипт подобного вида:

POST /user?id=1
password="abc";--

Многие базы данных SQL прочитают «--» как начало комментария, что приведёт к игнорированию последующего текста.

Что в итоге ? Всем пользователям установится пароль abc.

Что вы можете сделать, чтобы решить проблему?

Используйте подготовленный интерфейс PDO.

PDO - это уровень абстракции базы данных.

Он был встроен в PHP и предоставляет интерфейс, позволяющий использовать несколько баз данных.

PDO обеззараживает и встраивает внешние данные в SQL-запрос безопасным способом и избегает проблем, описанных выше.

Пользовательская информация

Весьма вероятно, что ваш сайт принимает от пользователей адреса электронной почты, номера телефонов, местоположение и другие предопределённые данные.

Разработчики PHP проделали замечательную работу по предвидению этих ситуаций и предоставили нам две функции.

Первая - filter_var (), вторая - filter_input ().

Эти две функции дезинфицируют входы, используя набор флагов.

Пример, который очень легко понять, - это когда вам нужно почистить электронную почту.

$email = 'myname@gmail.com';
$emailSanitized = filter_var($email, FILTER_SANITIZE_EMAIL);

Эта функция при использовании флага в этом примере гарантирует, что код удаляет все символы, кроме букв, цифр и следующих символов ! # $% & '* + - =? _` {|} ~ @. [] .

Проверка данных

Проверка не является очисткой, этот шаг не удаляет неверные данные, проверка подтверждает, что информация, поступающая в ваше приложение, соответствует вашим критериям.

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

В предыдущем примере с помощью флага FILTER_SANITIZE_EMAIL не поддерживаемые символы удалялись. Теперь мы можем использовать эту функцию с похожим флагом FILTER_VALIDATE_EMAIL .

Эта функция возвращает переменную двух разных типов в зависимости от переданной переменной.

Если проверка прошла успешно, она вернет само значение переменной, в противном случае она вернет false.

По этой причине нужно '! = False', чтобы проверить результат этой функции.

Согласно функции очистки большинство (если не все) флагов начинается со строки FILTER_VALIDATE_ * и заканчивается использованием типа проверки, который мы должны использовать.

Мы можем проверить целое число, число с плавающей запятой, IP-адреса, домены, URL и так далее.

Экранирование отображения данных

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

Мы можем добавить еще один уровень защиты к нашему приложению - при отображении данных исключать возможность показа некоторого кода и тем более его выполнение.

Чтобы избежать вывода кода, мы используем функцию PHP htmlentities.

Мы должны быть уверены, что второй параметр этой функции - флаг ENT_QUOTES, он экранирует одинарные и двойные кавычки, третий параметр определяет кодировку символов.

Обратите внимание, что нет необходимости постоянно экранировать данные, достаточно экранировать их либо при получении в начале, либо в конце при отображении.

Вот пример:

$script = '<script> alert("Это сообщение"); </script>';
echo htmlentities($script, ENT_QUOTES, 'UTF-8');

Подведем итоги:

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

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

Были ли сведения полезными?
6 
Продолжая использовать этот сайт и пользуясь нашими услугами, Вы соглашаетесь с Правилами и условиями веб-сайта и использованием файлов cookie на нашем веб-сайте. Также ознакомьтесь с нашей Политикой конфиденциальности, согласно которой, в заявленной степени, Вы соглашаетесь на обработку Ваших персональных данных.