Опасна ли опция PHP 'cgi.fix_pathinfo' с Nginx + PHP-FPM?

51

Там было много из говорить о вопросе безопасности по отношению к опции PHP используется с Nginx ( как правило , PHP-FPM, быстро CGI). cgi.fix_pathinfo

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

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

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

Вопросов

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

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

Totor
источник
1
Вы можете ответить на свой вопрос, поняв разницу между PATH_INFO и PATH_TRANSLATED: blogs.msdn.com/b/david.wang/archive/2005/08/04/…
Джованни Тирлони,

Ответы:

79

TL; DR - исправление (которое вам может даже не понадобиться) ОЧЕНЬ ПРОСТО и в конце этого ответа.

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

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

    • Информация о пути - это материал после сценария в URI (должен начинаться с косой черты, но заканчивается перед аргументами запроса, которые начинаются с a ?). Последний абзац в разделе обзора статьи Википедии о CGI подытоживает это. Ниже 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выглядела так: «/path/to/script.php/THIS/IS/PATH/INFO» в приведенном выше примере (с префиксом докрут как обычно).
    • С включенной 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 сервера. В этом примере он видит, что на вашем сервере у вас нет «/docroot/path/to/script.php/THIS», но у вас наверняка есть «/docroot/path/to/script.php», так что теперь SCRIPT_FILENAMEбыл определен и PATH_INFOполучает остальное.
    • Так что теперь хороший пример опасности, который подробно описан в документах Nginx и в ответе Хрвого Шполяра (вы не можете суетиться по поводу такого ясного примера), становится еще более ясным: на примере Хрвого (пример http: //). com / foo.jpg / nonexistent.php "), PHP видит файл в вашем docroot" /foo.jpg ", но не видит ничего с именем" /foo.jpg/nonexistent.php ", поэтому SCRIPT_FILENAMEполучает" /foo.jpg " (опять же с префиксом docroot) и PATH_INFOполучает "/nonexistent.php".
  • Почему и как это может быть опасно, теперь должно быть понятно:

    • Веб-сервер на самом деле не виноват - он просто передает URI в PHP, который невинно обнаруживает, что «foo.jpg» фактически содержит контент PHP, поэтому он выполняет его (теперь вы pwned!). Это НЕ частности, Nginx таковой.
  • РЕАЛЬНАЯ проблема заключается в том , что вы позволяете ненадежное содержимое будет загружено где - то без дезинфицирующего и вы позволяете другим произвольные запросы в том же месте, что PHP счастливо выполняет , когда это возможно.
  • Nginx и Apache могут быть построены или настроены для предотвращения запросов, использующих эту хитрость, и существует множество примеров того, как это сделать, в том числе в ответе пользователя user2372674 . Эта статья блога хорошо объясняет проблему, но в ней отсутствует правильное решение.

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

Решение

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

В противном случае найдите www.confфайл php-fpm (возможно /etc/php-fpm.d/www.conf, зависит от вашей системы). Убедитесь, что у вас есть это:

security.limit_extensions = .php

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

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

user109322
источник
5
Хороший ответ! Чтобы уточнить: если, как вы говорите, PHP определяет, что SCRIPT_FILENAMEесть, почему fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;в моей nginxконфе есть строка ? Переопределяет ли это усилие PHP по самостоятельному обнаружению ценности SCRIPT_FILENAME?
Тотор
Есть ли функция для получения значения security.limit_extensions? Я попробовал phpinfo(), ini_get(security.limit_extensions)и ini_get_all()без успеха.
elbowlobstercowstand
Спасибо, если последние версии PHP-FPM (~ 5.3.9 +?) Имеют это по умолчанию, зачем это нужно php7.1? Или эта статья не так?
Евгений Афанасьев
14

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

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

Хрвое Шполяр
источник
Вы повторяете только то, что можно прочитать по предоставленным мною ссылкам. Вы не объясняете реальный механизм. Ваш ответ нуждается в добавленной стоимости ИМХО.
Тотор
6
Это может быть правдой, но у вашего заголовка есть вопрос, и ответ на этот вопрос есть в моем ответе. Если вы хотите это явно; да это опасно; очень опасно.
Хрвое Шполяр,
1 / Мой ответ не ограничивается его названием: у него есть тело. 2 / user109322 доказали , что вы неправы: то , что значение , используемое для cgi.fix_pathinfoэто не опасно, так как конф по умолчанию php-fpmявляется безопасным (он будет выполнять только файлы с .phpрасширением).
Тотор
2

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

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

входит в блок местоположения. В других уроках

try_files $uri =404;

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

user2372674
источник