Чи дійсно параметр 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? ( докладні приклади)
  • Чи існує проблема ще в останніх версіях цих програм?
  • Чи вразливий Apache?

Я намагаюся зрозуміти проблему на кожному кроці. Наприклад, я не розумію, чому використання сокета php-fpm Unix може уникнути цієї проблеми.


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

Відповіді:


79

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як весь шебанг: "/path/to/script.php/THIS/IS/PATH/INFO" у наведеному вище прикладі (з префіксом докроот, як завжди).
    • Якщо увімкнено cgi.fix_pathinfo, PHP тепер правильно знаходить "/ THIS / IS / PATH / INFO" для вищевказаного прикладу PATH_INFOі SCRIPT_FILENAMEдодає його до та отримує лише ту частину, яка вказує на запит скрипта (з префіксом звичайно докрокота).
    • Примітка: коли 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 / noexistent.php "), PHP бачить файл на вашій docroot" /foo.jpg ", але він не бачить нічого з назвою" /foo.jpg/nonexistent.php "так SCRIPT_FILENAMEотримує" /foo.jpg " (знову ж, з префіксом docroot) і PATH_INFOотримує "/noexistent.php".
  • Чому і як це може бути небезпечно, тепер має бути зрозуміло:

    • Веб-сервер насправді не винен - ​​це просто наближення URI до PHP, який невинно виявляє, що "foo.jpg" насправді містить вміст PHP, тому він виконує його (тепер ви вже були виконані!). Це НЕ особливо для 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 і виконувати його за допомогою тієї ж методики. Ви все ще повинні мати хороший захист своїх програм.


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()без успіху.
ліктьовий локомотив

Дякую, якщо останні версії PHP-FPM (~ 5.3.9 +?) Мають це за замовчуванням, чому php7.1 потрібен? Або ця стаття неправильна?
Євген Афанасьєв

14

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

Що стосується використання php-fpm з unix-сокетом, щоб уникнути цього; IMO це не вирішить проблему.


Ви повторюєте лише те, що можна прочитати на наданих мені посиланнях. Ви не поясните реальний механізм. Ваша відповідь потребує IMHO з додатковою вартістю.
Тотор

6
Це може бути правдою, але у вашій назві є питання, і я відповів на це запитання. Якщо ви хочете це прямо? так, це небезпечно; дуже небезпечно.
Hrvoje Špoljar

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не повинно бути проблем. Більше інформації можна знайти тут .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.