PHP-FPM chroot

Szeretnék olyan php chroot-ot létrehozni, ahol a kód csak saját területét látja.
Ezt php-fpm segítségével majdnem meg is tudtam csinálni.
A pool konfigurációjában beállítottam a chroot értékét a user mappájára, valamint az apache-ból a


ProxyPassMatch "^/(.*\.php(/.*)?)$" "unix:/run/php/php7.0-fpm.sock|fcgi://localhost/public"

kóddal irányítottam át. (A SetHandler továbbítja a valódi document root értékét a kérelemben is.)
Szinte tökéletes, de a DOCUMENT_ROOT és CONTEXT_DOCUMENT_ROOT változók még így is a user mappájának eredeti, teljes útvonalát tartalmazzák. Akkor is, ha a pool konfigurációjában más értéket adok nekik.
El tudom valahogy teljesen rejteni a user elől a valódi mappáját?

Hozzászólások

Szerintem ehhez a webszervert is a chrootba kell tenni.

Fedora 27, Thinkpad x220

Elsőre elvetettem, amit írtál, de aztán elgondolkoztam rajta ... Ha arra gondolsz, hogy minden VirtualHost-ot chrootoljak, akkor nem is rossz gondolat.
Nem tudom, hogy a mod_unixd VirtualHost-okra is használható-e, de sajnos 9-es debian alatt már nem elérhető, így kipróbálni sem tudtam. Gondolom, annak is van oka, hogy kihagyták.
Ha van erre valamilyen támogatott eszköz, az azért érdekelne.

fejből nem tudom a konfigot, de úgy rémlik, hogy pl. nginx esetén, egészen jól szabályozható az is, hogy milyen változókat és milyen módon adjon át / rewrite-oljon adott esetben.

Ha nginx-ed van, én akkörül tapogatóznék.
Amennyire a default konfigot nézem: van neki egy fastcgi_params nevű konfigfájlja. Tipikusan azt include-olja be kb. mindenhova.
Abban rendszerint változtatás nélkül passzolja tovább a paramétereket, pl.:
fastcgi_param SCRIPT_FILENAME $request_filename;
Aztán, ezt lehet nem direktben átadni, hanem előtte mindenféle támogatott sztringmanipuláció elvégzése után passzolni csak.

Relatíve egyszerű, a PHP-FPM-ben poolonként tudsz chrootot definiálni. A chrootba be kell tenned pár dolgot, pl. tzdata fájlokat, különben random dolgok nem fognak működni. Az en file listam (ssh-s eszkozokkel egyutt): https://pastebin.com/X5qfiCeA

Nginx szinten a fastcgi_param sorokat kell megberhelni hogy minden útvonal a chroothoz képest relatív legyen, pl:


	location ~ \.php$ {
		try_files $uri =404;
		fastcgi_split_path_info ^(.+\.php)(/.+)$;
		fastcgi_index index.php;
		fastcgi_pass 127.0.0.1:9049;
		fastcgi_param SCRIPT_FILENAME /var/www/pasztor.at/htdocs$fastcgi_script_name;
		fastcgi_param QUERY_STRING $query_string;
		fastcgi_param REQUEST_METHOD $request_method;
		fastcgi_param CONTENT_TYPE $content_type;
		fastcgi_param CONTENT_LENGTH $content_length;
		fastcgi_param SCRIPT_NAME $fastcgi_script_name;
		fastcgi_param REQUEST_URI $request_uri;
		fastcgi_param DOCUMENT_URI $document_uri;
		fastcgi_param DOCUMENT_ROOT /var/www/pasztor.at/htdocs;
		fastcgi_param SERVER_PROTOCOL $server_protocol;
		fastcgi_param GATEWAY_INTERFACE CGI/1.1;
		fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
		fastcgi_param REMOTE_ADDR $remote_addr;
		fastcgi_param REMOTE_PORT $remote_port;
		fastcgi_param SERVER_ADDR $server_addr;
		fastcgi_param SERVER_PORT $server_port;
		fastcgi_param SERVER_NAME $server_name;
		fastcgi_param REDIRECT_STATUS 200;
		fastcgi_param HTTPS on;
		fastcgi_pass_header Authorization;
	}

Egy régi configból másoltam, úgyhogy nézd át. Ez esetben a /var/www/pasztor.at/htdocs a chrooton belüli útvonal.

Amúgy játszottam egy sort azzal hogy megpróbáltam belepatchelni a PHP-FPM-be a Linux namespaceket, stb. de sajnos elég kusza az architektúrája, szal 2 nap után feladtam. Alternatívaként indíthatsz vhostonként egy Docker containert benne egy külön PHP-FPM-el, de ez vhostonként külön memóriát igényel.

--
Pásztor János

Köszi, én is találtam pár ngix-es példát, és félek, itt az apache a gond. Nem találtam olyan apache beállítást, amivel módosítani tudnám ezeket az átadott fcgi paramétereket.

Az fpm konfigjában pedig hiába módosítom a DOCUMENT_ROOT környezeti változót, az létrejön, mint egy új környezeti változó, de a $_SERVER[DOCUMENT_ROOT] értéke nem módosul. Ha tudnám, hogy hogyan kell az env konfigurációs paranccsal a $_SERVER[DOCUMENT_ROOT] változótra hivatkozni, lehet, hogy az fpm konfigjából is megoldható lenne.

Apache eseten ezeket AFAIK nem tudod modositani, szal kerulo megoldas kell. Az egyik ilyen kerulo megoldas hogy csinalsz egy "vegtelen" symlinket, pl:

/var/www/pasztor.at/var/www/pasztor.at/var -> /var
(/var/www/pasztor.at a chroot konyvtar)

Ezzel elered azt, hogy a chrooton belul is ervenyes legyen az utvonal. Nem szep, de legalabb mukodik.

--
Pásztor János

Sajnos a .htaccess miatt kötve vagyok az apache-hoz.
Jól látom, hogy ez az FPM is valamilyen konténer, tehát annyi pool-t kell definiálnom, ahány elkülönített user-t akarok kiszolgálni, vagy van ennek valamilyen dinamikusan, kérelemidőben paraméterezhető formája is?

Ezeken a .htaccess-es dolgokon mindig felhúzom a szemöldököm: Miért vagy hozzá kötve?

Azért, mert a webdev évente kétszer hozzá akar nyúlni, és olyankor sem tudja mit akar, és 3-5 napot leszámláz avval, hogy try-and-error-t játszik vele?
Vagy valamilyen technikai indok, ami miatt megéri bevállalni ezt a szopást, hogy .htaccess egyáltalán engedélyezve legyen?

De a user miért szól bele technical decision-be?
Akkor üzemeltesse is, egyébként meg stfu.

Az nem "technikai" igény, hogy htaccess kell neki. Írja le, üljetek össze egy meetingre, definiálja a feladatot / problémát amit me akar oldani. De a hogyan meg legyen közösen eldöntve, vagy azáltal, akinek a f...ával a csalán van verve.

Az a tapasztalatom, az ilyen userektől, ha nem nyitott a párbeszédre, akkor jobb tőle megválni.

Érdekes félmegoldást találtam:
Ha az Apache konfigjában a SetEnv "DOCUMENT_ROOT" "/public" értéket beállítom, úgy a PHP a $_SERVER["DOCUMENT_ROOT"] értékének nem ezt látja, hanem a teljes útvonalat.
De, ha a SetEnv "document_root" "/public" értékadást használom, úgy a PHP-ban a $_SERVER tömbnek nem lesz "DOCUMENT_ROOT" indexe. Csak $_SERVER["document_root"], amiben szintén a teljes útvonal lesz elérhető.
Ezek után, ha az FPM pool konfigjában beállítom az env[DOCUMENT_ROOT]="/public" környezeti változó értéket, úgy a PHP már látni fogja a $_SERVER["DOCUMENT_ROOT"] változót is, aminek értéke most már a "/public" lesz. Igaz, megmarad a $_SERVER["document_root"] is a teljes útvonallal, valamint létrejön a DOCUMENT_ROOT környezeti változó is.
Ugyanez a CONTEXT_DOCUMENT_ROOT változóval is ugyanígy működik.
Mivel a jelenség eléggé definiálatlannak tűnik, élesben nem merném így használni, mert bármelyik frissítés módosíthat a működésen, de azért mindenképp érdekes.