Nepopsal bych tuto změnu jako "kritickou" jako takovou, ale stále má bezpečnostní důsledky. Nejsem si vědom ničeho, co by se zásadně změnilo od doby, kdy se tato rada stala relevantní - chování PHP silně směřuje ke zpětné kompatibilitě, i když to má bezpečnostní důsledky. Představte si, že máte server, který umožňuje lidem nahrávat soubory na server, řekněme do adresáře s názvem upload
. Nyní je váš skript pro nahrávání opatrný, aby povolil pouze soubory s určitými příponami (řekněme pouze .png
), aby nikdo nenahrál škodlivý soubor PHP.
Nyní se jako útočník pokusím zapsat PHP shell do souboru, pojmenujte soubor evil.png
a nahrajte jej. Až se nahraje, navštívím http://example.com/upload/evil.png
, ale zjistím, že mi to jen stáhne soubor -- nginx nikdy neodeslal požadavek do php-fcgi, aby byl zpracován jako php, protože název souboru končí .png
.
Pokud jsem útočník, který zná PATH_INFO
, dále zkusím http://example.com/upload/evil.png/index.php
. Pokud je váš server takto nakonfigurován, bude to mít za následek spuštění PHP (protože nginx vidí index.php
na konci) a PHP bude procházet cestou, dokud nenajde komponentu, kterou je soubor, nikoli adresář (evil.png
) a pokuste se jej provést. Pak je můj shell popraven a já vyhrávám.
Jak již bylo řečeno, existují lepší způsoby, jak se s tím vypořádat tak, že konfigurace NGINX předem rozdělí cestu, takže PHP nebude procházet souborovým systémem.
Z vynikajícího blogového příspěvku Neala Poolea k tomuto problému:
# Pass all .php files onto a php-fpm/php-fcgi server.
location ~ \.php$ {
# Zero-day exploit defense.
# http://forum.nginx.org/read.php?2,88845,page=3
# Won't work properly (404 error) if the file is not stored on this server, which is entirely possible with php-fpm/php-fcgi.
# Comment the 'try_files' line out if you set up php-fpm/php-fcgi on another machine. And then cross your fingers that you won't get hacked.
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php;
}
I nyní se zdá, že s sebou nese nebezpečí kvůli tomu, jak PHP stále zpracovává skript od 1. výskytu nalezeného souboru. Proč tedy ponechali výchozí hodnotu ;cgi.fix_pathinfo=1
pak?
Protože CGI je nezávislé na PHP a má svůj vlastní standard. CGI (Common Gateway Interface) je rozhraní, které instruuje server, jak komunikovat data s aplikacemi, jak jsou předávány informace a tělo požadavku ze vstupu na výstup. Webové servery lze nakonfigurovat tak, aby spouštěly program jako CGI
, což znamená, že předají data požadavku konkrétnímu programu. A tak NGinx předává požadavek PHP.
Když už mluvíme o standardu CGI , PHP-FPM
vývojáři musí splňovat standard CGI, jak je uvedeno v PHP-FPM
ini soubor ex:/etc/php/7.2/fpm/php.ini
:
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://php.net/cgi.fix-pathinfo
;cgi.fix_pathinfo=1
Předpokládám tedy text Setting this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting of zero causes PHP to behave as before.
vysvětluje výběr. Zde je PATH_INFO
Specifikace CGI.