PÖHÖPÖ

Disclaimer: Lehet, hogy tök fasság - mivel nem igazán sikerül hasonlót lelnem, de azt se hinném, hogy feltaláltam a kereket.

Na szóval, ha ne adj isten manapság phpzni*** kellene, mit tehet az ember ha olyan a projekt, hogy aszondja:
- legyen egy main app ahol a userek fájlokat hozhatnak létre - akár php-t is
- legyen a usereknek saját könyvtáruk projekteknek, miegymás és tudják tesztelni is
- egymás könyvtárába ne lássanak bele, ám a tesztet meg lehessen mutatni

A probléma az hogyan lehet elszeparálni a userek által megírt kódot - a fájlrendszer hozzáférésről van szó.

Van a phpban beállításokban egy a kezdő Joomlások és Drupalosok által nagyon utált, a shared hosztingok szent grálja opció ez pedig az open basedir. Ezt azt jelenti, hogy a direktva beállításán kívül eső elemeket a php nem fogja elérni.(Ha csak épp nem bugos). Ha hozzáférünk az inihez több könyvtárat is meglehet adni linux alatt : Windows alatt ; elválasztva. Sajnos ez nem valami mobil dolog, elvben mindig újra kéne indítani hozzá a rencert(szervert).

A PHP-ben 3 (4, de az a 3 valamelyike vagyis mindegy hol) féle mód van ini beállítást változtatni:

PHP_INI_SYSTEM - php.ini vagy a httpd.conf (vagy ennek megfelelője)
PHP_INI_USER - ez az amikor a kódban beírjuk hogy ini_set()
PHP_INI_PERDIR - ez egy viszonylag új dolog, amennyiben engedélyezve van, futáskor az útvonal minden könyvtárában a PHP ránéz egy (alapesetben) nevű .user.ini fájlra és az ide beírtakat megpróbálja figyelembe venni. (Ez ha minden igaz csak CGI/FAST-CGI futáskor számít, de ez a gyakoribb kiszolgáló konfig - ha nem tévedek.)

Beállítása válogatja, van amihez csak a php.iniben lévőt használja, van ahol enged szűkítést a fentiek valamelyikével.

Pl. az open basedir esetén, működő verzák:

php.ini - /var/www/customers/fizetos-ugyfel-123/web/home/domenje.hu: /temp/ : /session/
.user.ini - /var/www/customers/fizetos-ugyfel-123/web/home/domenje.hu/egykonyvtar/ : /temp/ : /session/
futáskor - /var/www/customers/fizetos-ugyfel-123/web/home/domenje.hu/egykonyvtar/egymasikkonyvtar/ : /temp/ : /session/

Include/require esetén az ini_set, /tavoli_konyvtar_ahol_szkript_van_/.user.ini dolgokat kihagyja, bármi is van oda firkálva a beillesztendő szkriptben.

Vissza térve a .user.inihez elég egy megadott könyvtárba bemásolni onnantól minden alkönyvtárra igaz lesz:

/var/www/customers/fizetos-ugyfel-123/web/home/domenje.hu/egykonyvtar/.user.ini

Viszont kell neki valamennyi idő mire aktiválódik - lásd egyéb php cache beállítások - csak utána lesz aktív. (Vannak neki saját cache ttlje is ez azonban csak a php.iniben állítható meg egyéb dolgai is.)

open_basedir="/var/www/customers/fizetos-ugyfel-123/web/home/domenje.hu/egykonyvtar/egymasikkonyvtar/"

Sajnos ennyi nem elég, mivel felül lehet írni egy másik alkönyvtárban lévő .user.ini fájllal. Hogy ezt megakadályozzuk, kell egy php fájl (aka block.php) meg kis módosítás az első user.iniben.

A block.php- legyen vmi ilyesmi:


<?php
$sd = dirname(getenv('SCRIPT_FILENAME'));

if(__DIR__ != $sd){
	chmod($sd . '/.user.ini', 0777);
	unlink($sd . '/.user.ini');
}
?>

Ezután az inihez adjuk hozzá ezt:

open_basedir="/var/www/customers/fizetos-ugyfel-123/web/home/domenje.hu/egykonyvtar/egymasikkonyvtar/"
auto_prepend_file="/var/www/customers/fizetos-ugyfel-123/web/home/domenje.hu/egykonyvtar/block.php"
auto_append_file="/var/www/customers/fizetos-ugyfel-123/web/home/domenje.hu/egykonyvtar/block.php"

Ezután bármilyen könyvtár is van az [egykonyvtar] folderben arra a szülőben elhelyezett .user.ini beállítások lesznek érvényesek. Amennyiben olyan a kód, hogy megpróbál a saját könyvtárában létrehozni .user.ini fájlt akkor a block.php törölni fogja. Ennél azért lehet szofisztikáltabb is a block.php, mert:
- vagy érdemes minden könyvtárat átnézni, hiszen attól még a fenti példában máshova létre lehet hozni és a prepend már hiába törli le.
- és/vagy kell 2 külön fájl ahol első szkript dob egy die()-t ha talál ilyen ini fájlt miután letörli.

Hozzászólások

> A probléma az hogyan lehet elszeparálni a userek által megírt kódot
> - a fájlrendszer hozzáférésről van szó.

man chmod

A POSIX modell egyszerű, mint a faék, de erre tökéletesen alkalmas még ACL-ek nélkül is. (Amit több felhasználónak közösen kell elérnie, arra ott vannak a csoport jogosultságok.)

Az open_basedir, disable_functions és hasonszőrű állatok lehet, hogy védelmet adnak bizonyos nem kívánatos tevékenységek ellen, de mérget azért ne vegyél rá. Ha valamit felhasználók között szeparálni kell, arra legalább oprendszer-szintű szeparációt használj - eltérő uid/gid.

A webszervernek pedig az adott felhasználók PHP kódjait a megfelelő jogosultságokkal kell futtatnia, erre több tucat implementáció létezik, pl. PHP-FPM, Apache MPM-ITK, stb.

Ha két felhasználó weboldalát tökéletesen szeparálni akarod, akkor nem elég csak az aktív tartalmat - jelen esetben: PHP programfájlokat - szeparálni, hiszen a weboldalak tartalmaznak statikus részeket (pl. képek, css, stb.) is, amiket a webszerver közvetlenül szolgál ki - ezeket a fájlokat szintén nem akarod world-readable módban hagyni és/vagy a webszervert root-ként futtatni.

Több megoldás van, nyilván az ember mást csinál egy tíz felhasználót kiszolgáló céges szerveren, mint egy sokezer felhasználót kiszolgáló "profi" környezetben.

Ha hirtelen gyors és frappáns megoldás kell, (és Apache-ot használsz), akkor első körben talán próbáld ki az MPM-ITK-t.

nincs két weboldal, nincs két webszerver

egy weboldal van, egy alkalmazásal, pár userrel - akik ilyenkor az általad javasolt megoldásokkal ellentétben ua azok a file tulajdonosok lesznek.

> akkor nem elég csak az aktív tartalmat - jelen esetben: PHP programfájlokat - szeparálni

saját könyvtár azt rak oda amit akar

[új] - No rainbow, no sugar - [új]

apachenak van apparmor modulja, tudsz minden vhosthoz sajat profilet megadni, azzal is eleg jol be lehet zarni az usert, es meg a binaris (/bin, stb) futtatast is jol le lehet korlatozni.

--
A vegtelen ciklus is vegeter egyszer, csak kelloen eros hardver kell hozza!

php-fpm chroot + valamint tiltanni egy par php fuggvenyt ( pl system, exec stb )