Проблемы безопасности в PHP, которые можно избежать

Проблемы безопасности в PHP, которые можно избежать

За время разработки на PHP очень часто приходится слышать высказывания такого рода: "PHP пока еще сырой язык", "PHP - скриптовый язык, не являющийся настоящим языком программирования" и т.п. Кроме того, существует мнение, что PHP - небезопасный язык, и его лучше не использовать. Конечно, PHP имеет свои проблемы, но не стоит забывать, что любой язык имеет свою область применения. Например, тот же Ruby имеет несколько важных уязвимостей, которые хорошо известны. Для Java так же существует свой список подобных проблем. Часто люди забывают, что не PHP создает небезопасный код, это делает разработчик.

PHP по своей природе "должен умирать" в конце каждого запроса. Таким образом, разработчикам не нужно заботиться о некоторых вещах, которые характерны для других языков. В настоящее время существуют несколько общих уязвимостей, которые должен знать PHP разработчик. Большинство наиболее общих из них можно найти в хорошо известном списке "OWASP Top 10 list". Здесь я приведу краткий обзор, того, как избежать некоторые из них.

SQL инъекции

Если вы отслеживаете уязвимости в своих приложениях, то вам должны быть известны статьи о взломах больших и маленьких компаний, основанные на уязвимости, известной, как "SQL injection" - SQL инъекции. Атаки такого рода основаны на том, что злоумышленник пытается получить доступ к приложению, используя в качестве части запроса специально сформированную строку с целью выполнения зловредных действий с базой данных.

К примеру, ваше приложение получает некоторые данные с использованием глобальной переменной $_GET. Если вы не экранируете или не фильтруете предоставляемые данные, то злоумышленник может записать в этот массив произвольные данные. Ужасно, не правда ли? Проблемы подобного рода, легко решаются при помощи слоя абстракции базы данных. Например, в PHP можно использовать PDO для этих целей. Вот небольшой пример, демонстрирующий описанное решение:

Метод bindParam самостоятельно "обезопасит" данные, хранимые в переменной $var. Также можно указать тип передаваемого значения. Обратите внимание, что данный вариант запроса отличается от варианта, когда запрос формируется в виде строки и параметры добавляются конкатенацией строк. Попробуйте представить, какие проблемы могут возникнуть, если запрос к базе сформировать примерно так:

Формирование запросов указанным способом - хороший и эффективный способ защиты от SQL инъекций.

Cross-Site Scripting (XSS) - Межсайтовый скриптинг

Под межсайтовым скриптингом понимается атака, в которой злоумышленник выводит пользователю на сайте-жертве вредоносную-информацию. К сожалению, данный тип атак в PHP продолжает работать и не существует стандартных методов для предотвращения данной атаки. Существует несколько путей для вывода введенной пользователем информации, такие как echo или printf, но не один из них по умолчанию на проверяет входную информацию автоматически. В замен этому, разработчику предлагается самому найти лучший способ для обработки пользовательской информации.

Ясно, что такое поведение имеет как плюсы, так и минусы. К положительным моментам можно отнести то, что разработчику не надо бороться с системой, которая может или не может сделать то, что ему требуется. Это дает большую гибкость, чтобы обработать информацию более корректно в конкретной ситуации. К сожалению, верно и обратное. Разработчику не составляет никакого труда не заботиться о фильтрации и валидации аргументов, и отправить информацию назад пользователю. Подумайте, что может случиться, если кем-то введенная строка выполнит JavaScript код, переданный в $_GET параметре:

Это довольно простой пример, но он оставляет открытой дверь для множества потенциально опасных атак, особенно если фильтрации нет вообще. Итак, что может PHP разработчик, чтобы предотвратить такие атаки? Как ни странно ответ на этот вопрос прост, чтобы говорить о нем, и гораздо более сложен, чтобы реализовать. Решение - фильтрация вводимых данных и экранирование выводимой информации.

К счастью, PHP имеет несколько инструментов, которые могут помочь уменьшить риск от атак данного рода. Первое, Фильтрация входных данных - PHP имеет несколько стандартных функций обработки строк, которые могут облегчить проверку входной информации. Среди этих функций одну можно выделить особенно, которая является не только гибкой, но и надежной - filter_var. Данная функция может быть использована, как для фильтрации, так и для валидации входных данных. Вот небольшой пример:

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

Хорошо, но это только ввод информации. А что можно сказать о выводе? Существует также несколько решений, которые могут помочь в решении данной проблемы.

  1. Использовать для вывода стандартную функцию htmlspecialchars. Данная функция осуществляет преобразование специальных символов в их HTML - представление. Необходимо быть уверенным, что данная функция вызвана со значением, требующим экранирования символов.
  2. Использование внешних библиотек обработки вывода. Существует масса шаблонизаторов для PHP. В качестве примера можно взглянуть на Symfony-связанный проект Twig. Twig по умолчанию экранирует вывод для предотвращения вредоносных инъекций в код HTML. Аналогично поступает, например, шаблонизатор {Macro} из фреймворка Limb3. Фактически вам требуется сообщить шаблонизатору, что для вывода конкретного значения необходимо отключить указанное поведение. Такое поведение уменьшает риск того, что вы пропустите что-нибудь где-нибудь.

Вообще есть постоянный совет, касающийся безопасности. Даже если вы реализовали что-то подобное Twig или {Macro}, то не думайте, что ваш сайт автоматически защищен от атак такого рода. Все библиотеки и инструменты имеют их собственные ограничения и дыры. Таким образом, вы все еще нуждаетесь в проверке, что фильтрация и экранизация вывода выполняется везде, а не "в большинстве мест". Для этих целей существует много инструментов, которые могут найти такие места.

Cross-Site Request Forgery

В завершение хочется поговорить об одном важном результате, который довольно широко распространен в веб-приложениях. Данный пункт справедлив не только PHP приложений. Мы будем говорить об уязвимости названной "cross-site request forgery" (CSRF). Данный тип уязвимости труден для обнаружения. При данной атаке используются собственные привилегии пользователя для выполнения скрипта на целевом сайте так, как если бы это выполнил он сам. Например, если есть ресурс/URL, который выдает права администратора другому пользователю. Доверчивого пользователя могут попросить кликнуть по специальной ссылке. В результате будет выполнено несанкционированное действие, и вы об этом не будете уведомлены.

Есть несколько путей, помогающих предупредить такие атаки в PHP приложениях, и они относительно просты для реализации. Первый путь - это скорее хороший совет, которого нужно придерживаться при создании вашего приложения и касается различий в HTTP командах. Если вы близко знакомы с HTTP запросами/ответами, то вам известно для чего нужны GET и POST. Если нет, то краткое пояснение: GET - это то, что обычно происходит, когда вы переходите по адресу, например, http://a-develop.ru в вашем браузере. Браузер просит сервер сформировать (дать, get) информацию для этой страницы и отправить ее обратно в браузер. POST - требуется для отправки (posting) данных на сервер.

CSRF атаки обычно связаны с уязвимостями GET URL, как целей. Практический совет, когда планируется приложение - сделать GET запросы идемпотентными. То есть выполнять их там, где они могут быть выполнены снова и снова без влияния на состояние приложения. Если вам требуется получить информацию от пользователя, или хотите, чтобы он изменил что-то необходимо использовать POST.

Такое решение не позволяет в полной мере защититься от данного вида атак. Хорошим решением является использование токена. Токен формируется на сессию пользователя (даже не зарегистрированного) или для каждого запроса токен формируется отдельно. Он представляет случайную строку. Далее сформированный токен добавляется в HTML форму в качестве скрытого параметра. После того, как пользователь отправил форму, она проверяется на сервере. В частности, сравнивается токен хранимый в сессии и полученный через форму - если они различны, то действие запрещается.

Как? Уже все?

В этой статье описаны три проблемы из названного выше списка OWASP Top 10. Остается еще 7, которые также являются важными проблемами. К счастью, существует множество статей помогающих защититься от них в PHP приложениях. Однако следует обращать внимание на даты статей, которые вы читаете. Некоторые из них могут быть устаревшими, и не смогут предоставить новейшее и надежное решение для поставленной задачи.

Надеюсь, я смог пролить свет не эти три важные проблемы. Безопасность приложения должна отслеживаться и проверяться разработчиками на каждом этапе создания приложения. Костыли, вставленные в конце разработки, ни к чему хорошему не приведут. Если вы пишете хороший, чистый и безопасный код с самого начала и используете эффективные средства, то многие проблемы вас беспокоить не будут!

Нет комментариев.
Добавить комментарий
Вам необходимо включить показ изображений в браузере для того чтобы увидеть код

Дайте нам знать, что вы - живой человек. Для нас это важно!
Кликните, если плохо видно

Прежде чем высказать свое мнение, прочитайте пожалуйста: правила

Рейтинг@Mail.ru