Назад | Перейти на главную страницу

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

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

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

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

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

Вопросы

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

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

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

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

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

    • На самом деле веб-сервер не виноват - он просто проксирует URI в PHP, который невинно обнаруживает, что "foo.jpg" действительно содержит содержимое PHP, поэтому он его выполняет (теперь вас обманули!). Это НЕ особенно для Nginx как такового.
  • В НАСТОЯЩИЙ Проблема в том, что вы позволяете загружать ненадежный контент куда-нибудь без очистки и разрешаете другие произвольные запросы в то же место, что PHP с радостью выполняет, когда это возможно.
  • Nginx и Apache могут быть созданы или настроены для предотвращения запросов, использующих эту уловку, и есть множество примеров того, как это сделать, в том числе в user2372674 ответ. Эта статья в блоге хорошо объясняет проблему, но не хватает правильного решения.

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

Решение

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

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

security.limit_extensions = .php

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

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

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

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

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

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

входит в блок локации. В других уроках

try_files $uri =404;

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