Опция PHP 'cgi.fix_pathinfo' действительно опасна с Nginx + PHP-FPM?

Был a партия из разговор о проблеме безопасности относительно cgi.fix_pathinfo Опция PHP используется с Nginx (обычно PHP-FPM, быстрый CGI).

В результате значение по умолчанию nginx конфигурационный файл раньше говорило:

# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

Однако теперь, "официальный" Nginx, Wiki указывает, что PATH_INFO может быть обработан правильно, не отключая вышеупомянутую опцию PHP.И что?

Вопросы

  • Можете Вы объяснять ясно, что делает cgi.fix_pathinfo ? (в официальном документе просто говорится: "Для получения дополнительной информации о PATH_INFO посмотрите спецификации CGI"),
  • Что PHP действительно сделает с ними PATH_INFO и SCRIPT_FILENAME переменные?
  • Почему и как это может быть опасно с Nginx? (подробные примеры)
  • Проблема все еще существует в последних версиях этих программ?
  • Действительно ли Apache уязвим?

Я пытаюсь понять проблему на каждом шаге. Например, я не понимаю, почему использование php-fpm сокета Unix могло избежать этой проблемы.

51
задан 23 May 2017 в 14:33
3 ответа

TL;DR - исправление (которое вам может даже не понадобиться) ОЧЕНЬ НЕЗАМЕДЛИТЕЛЬНО и в конце этого ответа.

Я постараюсь ответить на ваши конкретные вопросы, но ваше неправильное понимание того, что такое PATH_INFO, делает сами вопросы немного неправильными.

  • Первый вопрос должен быть "Что это за бизнес информации о пути?"

    • Информация о пути - это материал после скрипта в URI (должен начинаться с прямого слэша, но заканчиваться до аргументов запроса, который начинается с ?). Последний абзац обзорной части статьи Википедии о CGI прекрасно её резюмирует. Ниже PATH_INFO написано "/THIS/IS/PATH/INFO":

      http://example.com/path/to/script.php/THIS/IS/PATH/INFO?query_args=foo

  • Ваш следующий вопрос должен был быть: "Как PHP определяет, что такое PATH_INFO и SCRIPT_FILENAME? "

    • Ранние версии PHP были наивными и технически не поддерживали даже PATH_INFO, так что то, что должно было быть PATH_INFO было заряжено на SCRIPT_FILENAME, который, да, во многих случаях сломан. У меня нет достаточно старой версии PHP для тестирования, но я думаю, что она видела SCRIPT_FILENAME как весь shebang: "/path/to/script.php/THIS/IS/PATH/INFO" в приведенном выше примере (как обычно, с префиксом docroot).
    • С cgi. fix_pathinfo, PHP теперь правильно находит "/THIS/IS/PATH/INFO" для вышеприведенного примера и помещает его в PATH_INFO и SCRIPT_FILENAME получает только ту часть, которая указывает на запрашиваемый скрипт (конечно же, префикс с docroot).
    • Замечание: когда PHP начал поддерживать PATH_INFO, они должны были добавить настройки конфигурации для новой функции, чтобы люди, выполняющие скрипты, которые зависели от старого поведения, могли запускать новые версии PHP. Поэтому для этого даже есть переключатель конфигурации. Он должен был быть встроен (с "опасным" поведением) с самого начала.
  • Но откуда PHP знает, какая часть скрипта и каков его путь? Что если URI что-то вроде:

    http://example.com/path/to/script.php/THIS/IS/PATH/INFO.php?q=foo

    • Это может быть сложным вопросом в некоторых средах. Что происходит в PHP, так это то, что он находит первую часть пути URI, которая не соответствует ничему в докруте сервера. Для этого примера, он видит, что на вашем сервере нет "/docroot/path/to/script.php/THIS", но у вас, скорее всего, есть "/docroot/path/to/script.php", так что теперь SCRIPT_FILENAME определено, а PATH_INFO получает остальное.
    • Так что теперь хороший пример опасности, который хорошо описан в Nginx docs и в Hrvoje Špoljar's answer (Вы не можете суетиться по поводу такого ясного примера), становится еще более ясным: приведем пример Hrvoje ("http://example.com/foo. jpg/nexistent.php "), PHP видит файл в вашем docroot "/foo.jpg", но не видит ничего под названием "/foo.jpg/nexistent.php", так что SCRIPT_FILENAME получает "/foo.jpg" (опять же, с префиксом docroot) и PATH_INFO получает "/nexistent". php".
  • Почему и как это может быть опасно теперь должно быть ясно:

    • Веб-сервер на самом деле не виноват - он просто проксирует URI к PHP, который невинно обнаруживает, что "foo.jpg" на самом деле содержит содержимое PHP, поэтому он выполняет его (теперь вас прогнали!). Это NOT особенность Nginx как такового.
  • Проблема REAL заключается в том, что вы позволяете загружать куда-нибудь недоверенное содержимое без дезинфекции и разрешаете другие произвольные запросы в то же самое место, которое PHP счастливо выполняет, когда может.
  • Nginx и Apache могут быть собраны или сконфигурированы так, чтобы предотвратить запросы, использующие эту хитрость, и для этого есть множество примеров, в том числе в ответе user2372674. Эта статья в блоге хорошо объясняет проблему, но в ней отсутствует правильное решение.

  • Однако, лучшее решение - это просто убедиться, что PHP-FPM настроен правильно, чтобы он никогда не выполнял файл, если только он не заканчивается на ".php". Стоит отметить, что последние версии PHP-FPM (~5.3.9+?) имеют такую конфигурацию по умолчанию, так что эта опасность больше не является проблемой.

The Solution

Если у вас есть последняя версия PHP-FPM (~5.3.9+? ), то вам ничего не нужно делать, так как приведенное ниже безопасное поведение уже по умолчанию.

Иначе найдите файл php-fpm's www.conf (может быть /etc/php-fpm.d/www.conf, зависит от вашей системы). Убедитесь, что у вас есть следующее:

security.limit_extensions = .php

Опять же, это во многих местах по умолчанию в наши дни.

Обратите внимание, что это не мешает злоумышленнику загрузить ".php" файл в папку WordPress и выполнить его, используя ту же самую технику. Вам все еще нужна хорошая безопасность для ваших приложений.

80
ответ дан 28 November 2019 в 19:36

В сущности без этого вы можете загрузить файл с php кодом с именем 'foo.jpg' на веб-сервер; затем запросить его как http://domain.tld/foo.jpg/nonexistent.php и стек веб-сервера ошибочно скажет oh; это PHP; мне нужно обработать это, он не сможет найти foo.jpg/nexistent.php, так что он вернется к foo.jpg и обработает foo.jpg как php код. Это опасно, так как открывает систему для очень легкого вторжения; любое веб-приложение, позволяющее, например, загружать образы, становится инструментом для загрузки бэкдора.

Относительно использования php-fpm с unix-сокетом, чтобы избежать этого; IMO это не решит проблему.

.
14
ответ дан 28 November 2019 в 19:36

В вики Nginx в качестве меры безопасности

if (!-f $document_root$fastcgi_script_name) {
    return 404;
}

включена в блок локации. В других учебниках используется

try_files $uri =404;

, которая должна сделать то же самое, но может дать проблемы в соответствии с вики Nginx. С этими опциями cgi.fix_pathinfo=1 больше не должно быть проблем. Больше информации можно найти здесь .

.
2
ответ дан 28 November 2019 в 19:36

Теги

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