Vraag Is de PHP-optie 'cgi.fix_pathinfo' echt gevaarlijk met Nginx + PHP-FPM?


Er is geweest een  lot  van  pratend over een beveiligingsprobleem ten opzichte van de cgi.fix_pathinfo PHP-optie gebruikt met Nginx (meestal PHP-FPM, snelle CGI).

Als gevolg hiervan werd het standaard nginx-configuratiebestand gebruikt om te zeggen:

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

Nu echter, de "officiële" Nginx-wiki zegt dat PATH_INFO kan correct worden afgehandeld zonder de bovenstaande PHP-optie uit te schakelen. En dan?

vragen

  • Kun je duidelijk uitleggen wat wel cgi.fix_pathinfo do? (officiële doc zegt gewoon: "Zie de CGI-specificaties voor meer informatie over PATH_INFO")
  • Wat gaat PHP hier echt mee doen PATH_INFO en SCRIPT_FILENAME variabelen?
  • Waarom en hoe kan het gevaarlijk zijn met Nginx? (gedetailleerd voorbeelden)
  • Is het probleem nog steeds aanwezig in recente versies van deze programma's?
  • Is Apache kwetsbaar?

Ik probeer het probleem bij elke stap te begrijpen. Ik begrijp bijvoorbeeld niet waarom de php-fpm Unix-socket wordt gebruikt zou kunnen vermijden dit probleem.


40
2017-09-11 17:35


oorsprong


U kunt uw eigen vraag beantwoorden door het verschil tussen PATH_INFO en PATH_TRANSLATED te begrijpen: blogs.msdn.com/b/david.wang/archive/2005/08/04/... - Giovanni Tirloni


antwoorden:


TL; DR - de oplossing (die je misschien niet eens nodig hebt) is ZEER EENVOUDIG en aan het einde van dit antwoord.

Ik zal proberen je specifieke vragen te beantwoorden, maar je misverstand over wat PATH_INFO is, maakt de vragen zelf een beetje verkeerd.

  • De eerste vraag zou moeten zijn: "Wat is dit pad info bedrijf?"

  • Je volgende vraag zou moeten zijn: "Hoe bepaalt PHP wat? PATH_INFO en SCRIPT_FILENAME zijn?"

    • Eerdere versies van PHP waren naïef en ondersteunden technisch gezien niet eens PATH_INFO, dus wat zou moeten zijn PATH_INFO werd op munged gemunt SCRIPT_FILENAME wat in veel gevallen inderdaad verbroken is. Ik heb geen oud genoeg versie van PHP om mee te testen, maar ik geloof dat het zag SCRIPT_FILENAME als de hele map: "/path/to/script.php/THIS/IS/PATH/INFO" in het bovenstaande voorbeeld (voorafgegaan door de docroot zoals gebruikelijk).
    • Met cgi.fix_pathinfo ingeschakeld, vindt PHP nu correct "/ THIS / IS / PATH / INFO" voor het bovenstaande voorbeeld en plaatst het in PATH_INFO en SCRIPT_FILENAME krijgt alleen het gedeelte dat verwijst naar het script dat wordt aangevraagd (voorafgegaan door de docroot natuurlijk).
    • Opmerking: toen PHP rondging om daadwerkelijk te ondersteunen PATH_INFO, ze moesten een configuratie-instelling toevoegen voor de nieuwe functie, zodat mensen met scripts die afhankelijk waren van het oude gedrag, nieuwe PHP-versies konden uitvoeren. Daarom is er zelfs een configuratieschakelaar voor. Het had vanaf het begin moeten zijn ingebouwd (met het "gevaarlijke" gedrag).
  • Maar hoe weet PHP welk deel het script is en wat het padinfo is? Wat als de URI iets is als:

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

    • Dat kan in sommige omgevingen een complexe vraag zijn. Wat er in PHP gebeurt, is dat het het eerste deel van het URI-pad vindt dat niet overeenkomt met iets onder de docroot van de server. Voor dit voorbeeld ziet het dat u op uw server niet "/docroot/path/to/script.php/THIS" hebt, maar u hebt zeker "/docroot/path/to/script.php", dus nu SCRIPT_FILENAME is bepaald en PATH_INFO krijgt de rest.
    • Dus nu het goede voorbeeld van het gevaar dat mooi gedetailleerd is in de Nginx-documenten en in Hrvoje Špoljar's antwoord (je kunt niet zo kieskeurig zijn over zo'n duidelijk voorbeeld) wordt nog duidelijker: gezien Hrvoje's voorbeeld ("http://example.com/foo.jpg/nonexistent.php "), PHP ziet een bestand op je docroot" /foo.jpg ", maar het ziet niet zoiets als" /foo.jpg/nonexistent.php "dus SCRIPT_FILENAME krijgt "/foo.jpg" (opnieuw, voorafgegaan door docroot) en PATH_INFO krijgt "/nonexistent.php".
  • Waarom en hoe het gevaarlijk kan zijn, moet nu duidelijk zijn:

    • De webserver is echt niet fout - het is slechts de URI naar PHP proxy, die onschuldig vindt dat "foo.jpg" eigenlijk PHP inhoud bevat, dus het voert het uit (nu heb je een pwned!). Dit is NIET met name voor Nginx als zodanig.
  • De REAL Het probleem is dat je niet-vertrouwde inhoud ergens naartoe uploadt zonder te ontsmetten en je andere willekeurige verzoeken naar dezelfde locatie toestaat, die PHP graag uitvoert wanneer dit kan.
  • Nginx en Apache kunnen worden gebouwd of geconfigureerd om verzoeken te voorkomen met behulp van deze truc, en er zijn voldoende voorbeelden om dit te doen, ook in user2372674's antwoord. Dit blogartikel verklaart het probleem mooi, maar het mist de juiste oplossing.

  • De beste oplossing is echter om ervoor te zorgen dat PHP-FPM correct is geconfigureerd, zodat het nooit een bestand zal uitvoeren tenzij het eindigt met ".php". Het is vermeldenswaard dat recente versies van PHP-FPM (~ 5.3.9 +?) Dit standaard hebben, dus dit gevaar is niet zozeer meer een probleem.

De oplossing

Als u een recente versie van PHP-FPM (~ 5.3.9 +?) Heeft, hoeft u niets te doen, omdat het onderstaande veilige gedrag al standaard is.

Zoek anders php-fpm's www.conf bestand (misschien /etc/php-fpm.d/www.conf, hangt af van uw systeem). Zorg ervoor dat je dit hebt:

security.limit_extensions = .php

Nogmaals, dat is tegenwoordig de standaard op veel plaatsen.

Merk op dat dit een aanvaller er niet van weerhoudt om een ​​".php" -bestand te uploaden naar een map met WordPress-uploads en dat bestand met dezelfde techniek uit te voeren. U moet nog steeds een goede beveiliging hebben voor uw toepassingen.


61
2018-06-25 04:09



Goed antwoord! Ter verduidelijking: als, zoals u zegt, PHP bepaalt wat SCRIPT_FILENAME is, waarom is er een fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; regel in mijn nginx conf? Heeft dit voorrang op de inspanningen van PHP om de waarde van te ontdekken SCRIPT_FILENAME alleen? - Totor
Is er een functie om de waarde van te krijgen security.limit_extensions? ik probeerde phpinfo(), ini_get(security.limit_extensions), en ini_get_all() zonder succes. - elbowlobstercowstand


In wezen zonder dit kun je een bestand met php-code genaamd 'foo.jpg' uploaden naar de webserver; vraag het dan als http: //domain.tld/foo.jpg/nonexistent.php en de webserverstack zal abusievelijk zeggen oh; dit is een PHP; Ik moet dit verwerken, het zal foo.jpg / nonexistent.php niet vinden, dus het zal terugvallen op foo.jpg en foo.jpg verwerken als php-code. Dat is gevaarlijk omdat het systeem wordt geopend voor zeer eenvoudige inbraak; elke webtoepassing die beelduploads toestaat, wordt bijvoorbeeld een tool om backdoor te uploaden.

Wat betreft het gebruik van php-fpm met unix socket om dit te voorkomen; IMO het zal het probleem niet oplossen.


12
2017-09-12 10:04



U herhaalt alleen wat er te lezen is op de links die ik heb verstrekt. Je legt het echte mechanisme niet uit. Uw antwoord heeft een toegevoegde waarde IMHO. - Totor
Dat kan waar zijn, maar je titel heeft vraag en antwoord op die vraag zit in mijn antwoord. Als je het expliciet wilt; ja het is gevaarlijk; zeer gevaarlijk. - Hrvoje Špoljar
1 / Mijn antwoord beperkt zich niet tot de titel: het heeft een lichaam. 2 / user109322 heeft bewezen dat je ongelijk hebt: voor welke waarde dan ook cgi.fix_pathinfo is niet gevaarlijk, omdat de standaard conf. van php-fpm is veilig (het voert alleen bestanden uit met de .php uitbreiding). - Totor


In de Nginx-wiki als veiligheidsmaatregel

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

is opgenomen in het locatieblok. In andere zelfstudies

try_files $uri =404;

wordt gebruikt, wat hetzelfde zou moeten doen, maar kan problemen geven volgens de Nginx-wiki. Met deze opties, cgi.fix_pathinfo=1 zou geen probleem meer moeten zijn. Meer informatie is te vinden hier.


1
2018-06-24 13:47