Ist die PHP-Option 'cgi.fix_pathinfo' mit Nginx + PHP-FPM wirklich gefährlich?

51

Es gab eine Menge von sprechen über ein Sicherheitsproblem in Bezug auf die cgi.fix_pathinfoPHP - Option mit Nginx verwendet ( in der Regel PHP-FPM, schneller CGI).

Infolgedessen wird in der Standard-Nginx-Konfigurationsdatei Folgendes angegeben:

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

Das "offizielle" Nginx-Wiki gibt jedoch jetzt an, dass PATH_INFO korrekt gehandhabt werden kann, ohne die obige PHP-Option zu deaktivieren. Na und?

Fragen

  • Können Sie klar erklären, was zu cgi.fix_pathinfotun ist? (Das offizielle Dokument sagt nur : "Weitere Informationen zu PATH_INFO finden Sie in den CGI-Spezifikationen.")
  • Was macht PHP wirklich mit diesen PATH_INFOund SCRIPT_FILENAMEVariablen?
  • Warum und wie kann es mit Nginx gefährlich sein? ( detaillierte Beispiele)
  • Gibt es das Problem in neueren Versionen dieser Programme noch?
  • Ist Apache anfällig?

Ich versuche, das Problem bei jedem Schritt zu verstehen. Ich verstehe zum Beispiel nicht, warum die Verwendung des Unix-Sockets php-fpm dieses Problem vermeiden könnte .

Totor
quelle
1
Sie können Ihre eigene Frage beantworten, indem Sie den Unterschied zwischen PATH_INFO und PATH_TRANSLATED verstehen: blogs.msdn.com/b/david.wang/archive/2005/08/04/…
Giovanni Tirloni

Antworten:

79

TL; DR - das Update (das Sie möglicherweise nicht einmal benötigen) ist SEHR EINFACH und am Ende dieser Antwort.

Ich werde versuchen, Ihre spezifischen Fragen zu beantworten, aber Ihr Missverständnis von PATH_INFO macht die Fragen selbst ein bisschen falsch.

  • Die erste Frage sollte lauten: "Was ist das für ein Pfadinformationsgeschäft?"

  • Ihre nächste Frage hätte lauten sollen: "Wie bestimmt PHP was PATH_INFOund was SCRIPT_FILENAMEist?"

    • Frühere PHP-Versionen waren naiv und unterstützten technisch nicht einmal PATH_INFO, so dass das, was eigentlich sein PATH_INFOsollte, aufgemischt wurde, SCRIPT_FILENAMEwas in vielen Fällen defekt ist. Ich habe keine ausreichend alte Version von PHP zum Testen, aber ich glaube, sie hat SCRIPT_FILENAMEim obigen Beispiel Folgendes gesehen: "/path/to/script.php/THIS/IS/PATH/INFO" (vorangestellt mit die docroot wie gewohnt).
    • Mit cgi.fix_pathinfo aktiviert ist , findet PHP jetzt richtig „/ THIS / IS / PATH / INFO“ für das obige Beispiel und Puts hinein PATH_INFOund SCRIPT_FILENAMEbekommt nur den Teil , dass die Punkte an das Skript (mit dem Präfix der docroot natürlich) angefordert werden.
    • Hinweis: Als PHP tatsächlich unterstützt wurde PATH_INFO, mussten sie eine Konfigurationseinstellung für die neue Funktion hinzufügen, damit Benutzer, die Skripts ausführen, die vom alten Verhalten abhängen, neue PHP-Versionen ausführen können. Deshalb gibt es sogar einen Konfigurationsschalter dafür. Es sollte von Anfang an eingebaut sein (mit dem "gefährlichen" Verhalten).
  • Aber woher weiß PHP, welcher Teil des Skripts ist und welche Pfadinformationen es enthält? Was ist, wenn der URI ungefähr so ​​aussieht:

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

    • Das kann in manchen Umgebungen eine komplexe Frage sein. Was in PHP passiert, ist, dass es den ersten Teil des URI-Pfades findet, der nichts unter der Docroot des Servers entspricht. In diesem Beispiel sehen Sie, dass Sie auf Ihrem Server nicht "/docroot/path/to/script.php/THIS" haben, aber Sie haben mit Sicherheit "/docroot/path/to/script.php" SCRIPT_FILENAMEwurde bestimmt und PATH_INFObekommt den rest.
    • Das gute Beispiel für die Gefahr, die in den Nginx-Dokumenten und in der Antwort von Hrvoje Špoljar (Sie können sich über ein so klares Beispiel nicht im Klaren sein) ausführlich beschrieben wird, wird jetzt noch deutlicher: anhand des Beispiels von Hrvoje (" http: // example. com / foo.jpg / nonexistent.php "), PHP sieht eine Datei auf Ihrem docroot" /foo.jpg ", aber es sieht nichts mit dem Namen" /foo.jpg/nonexistent.php "so SCRIPT_FILENAMEbekommt" /foo.jpg " (wieder mit dem Präfix docroot) und PATH_INFOerhält "/nonexistent.php".
  • Warum und wie gefährlich es sein kann, sollte jetzt klar sein:

    • Der Webserver ist wirklich nicht schuld - er gibt lediglich den URI an PHP weiter, der unschuldigerweise feststellt, dass "foo.jpg" tatsächlich PHP-Inhalt enthält, und führt ihn aus (jetzt sind Sie pwned!). Dies gilt NICHT speziell für Nginx an sich.
  • Das WIRKLICHE Problem ist, dass Sie nicht vertrauenswürdigen Inhalt an einen beliebigen Ort hochladen lassen, ohne ihn zu bereinigen, und dass Sie andere willkürliche Anforderungen an denselben Ort zulassen, den PHP gerne ausführt, wenn es kann.
  • Nginx und Apache könnten so erstellt oder konfiguriert werden, dass Anfragen mit diesem Trick verhindert werden. Es gibt zahlreiche Beispiele dafür, auch in der Antwort von user2372674 . Dieser Blogartikel erklärt das Problem gut, aber es fehlt die richtige Lösung.

  • Die beste Lösung ist jedoch, einfach sicherzustellen, dass PHP-FPM richtig konfiguriert ist, damit es niemals eine Datei ausführt, es sei denn, sie endet mit ".php". Es ist erwähnenswert, dass neuere Versionen von PHP-FPM (~ 5.3.9 +?) Dies als Standard haben, daher ist diese Gefahr nicht mehr so ​​problematisch.

Die Lösung

Wenn Sie eine neuere Version von PHP-FPM (~ 5.3.9 +?) Haben, müssen Sie nichts unternehmen, da das unten stehende sichere Verhalten bereits die Standardeinstellung ist.

Andernfalls suchen Sie die www.confDatei von php-fpm ( /etc/php-fpm.d/www.confhängt möglicherweise von Ihrem System ab). Stellen Sie sicher, dass Sie Folgendes haben:

security.limit_extensions = .php

Auch dies ist heutzutage an vielen Orten Standard.

Beachten Sie, dass dies einen Angreifer nicht daran hindert, eine ".php" -Datei in einen WordPress-Upload-Ordner hochzuladen und diese mit derselben Technik auszuführen. Sie müssen weiterhin über eine gute Sicherheit für Ihre Anwendungen verfügen.

user109322
quelle
5
Gute Antwort! Zur Verdeutlichung: Wenn, wie Sie sagen, PHP bestimmt, was SCRIPT_FILENAMEist, warum ist fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;in meiner nginxconf eine Zeile ? Überschreibt es die Bemühungen von PHP, den Wert SCRIPT_FILENAMEvon sich selbst zu entdecken ?
Totor
Gibt es eine Funktion, deren Wert ermittelt werden soll security.limit_extensions? Ich habe es versucht phpinfo(), ini_get(security.limit_extensions)und ini_get_all()ohne Erfolg.
Elbowlobstercowstand
Vielen Dank, wenn aktuelle Versionen von PHP-FPM (~ 5.3.9 +?) Dies als Standard haben, warum braucht PHP7.1 es? Oder ist dieser Artikel falsch?
Yevgeniy Afanasyev
14

Im Wesentlichen können Sie ohne diese Datei mit PHP-Code namens "foo.jpg" auf den Webserver hochladen; Dann fordern Sie es wie http: //domain.tld/foo.jpg/nonexistent.php an und der Web-Server-Stack sagt fälschlicherweise oh; das ist ein PHP; Ich muss das verarbeiten, es wird foo.jpg / nonexistent.php nicht finden, also wird es auf foo.jpg zurückgreifen und foo.jpg als PHP-Code verarbeiten. Das ist gefährlich, da es das System für ein sehr leichtes Eindringen öffnet. Jede Webanwendung, die zum Beispiel das Hochladen von Bildern ermöglicht, wird zum Tool zum Hochladen von Backdoors.

In Bezug auf die Verwendung von PHP-FPM mit Unix-Socket, um dies zu vermeiden; IMO wird es das Problem nicht lösen.

Hrvoje Špoljar
quelle
Sie wiederholen nur das, was auf den von mir bereitgestellten Links zu lesen ist. Sie erklären nicht den wirklichen Mechanismus. Ihre Antwort braucht IMHO einen Mehrwert.
Totor
6
Das mag stimmen, aber Ihr Titel hat Frage und Antwort auf diese Frage ist in meiner Antwort. Wenn Sie es ausdrücklich wollen; ja es ist gefährlich; sehr gefährlich.
Hrvoje Špoljar
1 / Meine Antwort ist nicht auf den Titel beschränkt: Sie hat einen Körper. 2 / user109322 hat bewiesen, dass Sie falsch liegen: Der Wert, für den verwendet wird, cgi.fix_pathinfoist nicht gefährlich, da die Standardkonfiguration sicher php-fpmist (es werden nur Dateien mit der .phpErweiterung ausgeführt).
Totor
2

Im Nginx-Wiki als Sicherheitsmaßnahme

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

ist im Standortblock enthalten. In anderen Tutorials

try_files $uri =404;

verwendet wird, was das gleiche tun sollte, kann aber laut Nginx-Wiki Probleme bereiten. Mit diesen Optionen cgi.fix_pathinfo=1sollte das kein Problem mehr sein. Weitere Informationen finden Sie hier .

user2372674
quelle