Stručne: Používateľ webservera, pod ktorým beží PHP, by mal podľa princípu minimálnych práv (Least Privilege) čítať len to, čo web potrebuje, a zapisovať len tam, kde ukladá dáta. Nemá prihlasovací shell, práva sudo, vlastné úlohy cron ani kľúče SSH a jeho databázový účet smie údaje iba čítať a meniť. Možnosti systemd ako ProtectSystem a PrivateTmp PHP-FPM ďalej obmedzujú.
Otázka po vlámaní: čo smie tento proces?
PHP2Shell je o vzdialenom spustení škodlivého kódu bez prihlásenia. Ak sa to podarí, kód nebeží vo vzduchoprázdne, ale ako celkom konkrétny používateľ: používateľ procesu PHP. Všetko, čo tento používateľ smie, smie od tej chvíle aj útočník.
Na mnohých serveroch je to prekvapivo veľa. Používateľ vlastní celý programový kód, má shell, môže zakladať vlastné úlohy cron a databázový účet aplikácie má všetky práva na všetky databázy. Pre útočníka je to ideálny východiskový stav, aby sa usadil natrvalo.
Ako správne prideliť súbory a priečinky, opisuje sprievodca Práva k súborom na webovom serveri. Tento článok sa zameriava na samotný účet: prihlásenie, osobitné práva, plánované úlohy, databázu a hranice, ktoré určuje systemd.
Inventúra: kto je používateľ webservera?
Najprv zistite, ktorí používatelia sú vôbec zapojení. Pri PHP-FPM určuje každý pool pomocou user a group, pod kým bežia jeho workery. Pri mod_php beží PHP ako používateľ Apache. Ako spolupracujú master a workery pri PHP-FPM, vysvetľuje PHP-FPM jednoducho: správca procesov, pooly a workery. Nasledujúce príkazy iba čítajú:
# Pod akými používateľmi bežia webserver a PHP?
ps -eo user,group,cmd | grep -E "[p]hp-fpm|[n]ginx|[a]pache2|[h]ttpd" | sort | uniq -c
# Údaje o účte: domovský priečinok a shell (upraviť používateľa)
getent passwd www-data
# Má používateľ práva sudo?
sudo -l -U www-data
# Vlastné úlohy cron?
sudo crontab -l -u www-data
# Kľúče SSH v domovskom priečinku (pri Debiane/Ubuntu je to /var/www)
sudo ls -la /var/www/.ssh 2>/dev/null
Výsledky si zapíšte pre každého používateľa poolu. Ak všetky weby bežia pod tým istým používateľom, je to prvý bod na zozname; ako ich oddeliť, opisuje Izolácia poolov PHP-FPM pre každý web.
Práva používateľa webservera: čo účet nepotrebuje
Nasledujúci prehľad ukazuje, čo používateľ webservera typicky nepotrebuje a ako mu to odobrať.
| Právo | Prečo je nebezpečné | Odporúčanie |
|---|---|---|
| Prihlasovací shell | možné prihlásenie a interaktívne používanie | shell /usr/sbin/nologin |
| záznamy sudo | cesta k právam root | žiadne záznamy, ani pre jednotlivé príkazy |
| vlastný crontab | trvalé zadné vrátko, ktoré prežije každý reštart | žiadny, obmedziť cez /etc/cron.allow |
| kľúče SSH | prihlásenie zvonka | žiadne authorized_keys |
| vlastníctvo programového kódu | kód sa dá zmeniť | vlastníkom je používateľ pre nasadzovanie |
| práva zápisu mimo dátových priečinkov | ukladanie škodlivého kódu | len uploady, cache, temp |
| plné práva k databáze | databázy iných aplikácií, prístup k súborom cez databázu | len vlastná databáza, len práva k údajom |
Shell nastavíte príkazom usermod -s /usr/sbin/nologin www-data. Pre cron platí: ak existuje /etc/cron.allow, smú vlastné úlohy cron zakladať len tam uvedení používatelia. Novo založené úlohy cron alebo neznáme kľúče SSH sú typickým znakom toho, že sa niekto usadil. Obzvlášť zreteľné varovanie opisuje článok Varovný signál: webserver spúšťa shell.
Databáza: obmedziť práva na nevyhnutné
Databázový účet webu je fakticky druhý používateľ webservera. Jeho prístupové údaje ležia v konfiguračnom súbore aplikácie a votrelecký kód ich môže čítať. Preto by mal smieť len to, čo aplikácia v prevádzke potrebuje.
-- Príklad MySQL/MariaDB: vlastný účet pre každý web, len práva k údajom
CREATE USER 'seite1'@'localhost' IDENTIFIED BY 'hier-ein-langes-Zufallspasswort';
GRANT SELECT, INSERT, UPDATE, DELETE ON seite1.* TO 'seite1'@'localhost';
-- Skontrolovať práva
SHOW GRANTS FOR 'seite1'@'localhost';
Práva ako FILE, SUPER alebo GRANT OPTION a prístup k *.* aplikačný účet nepotrebuje. Mnohé CMS potrebujú pri aktualizáciách navyše CREATE, ALTER, INDEX a DROP. Čistejší je oddelený účet pre aktualizácie a migrácie, ktorý sa používa len počas údržby. Požiadavky si overte v dokumentácii výrobcu.
PHP-FPM ďalej obmedziť pomocou systemd
systemd dokáže obmedziť pohľad služby na systém. Pre PHP-FPM sa z dokumentácie systemd hodí niekoľko možností obzvlášť dobre. Pôsobia aj na hlavný proces, ktorý štartuje ako root.
# sudo systemctl edit php8.3-fpm
[Service]
# /usr, /boot a /etc len na čítanie
ProtectSystem=full
# /home, /root a /run/user neviditeľné
ProtectHome=true
# vlastný /tmp a /var/tmp len pre túto službu
PrivateTmp=true
# žiadne rozšírenie práv cez setuid alebo capabilities súborov
NoNewPrivileges=true
Tieto možnosti pred ostrým nasadením otestujte. Ak weby ležia pod /home, ProtectHome=true znemožní prístup. NoNewPrivileges=true môže rušiť programy, ktoré PHP volá a ktoré pri štarte menia svoje skupinové práva, napríklad niektoré lokálne poštové programy pre funkciu PHP mail(). Postupujte preto po krokoch:
- Doplniť jednu možnosť, reštartovať službu, skontrolovať
systemctl status php8.3-fpm. - Otestovať kľúčové funkcie webu: prihlásenie, formuláre, odosielanie pošty, uploady, úlohy cron aplikácie.
- Vyhodnotiť chybový protokol PHP-FPM a aplikácie.
- Až potom doplniť ďalšiu možnosť.
Na záver socket: podľa príručky PHP dostáva štandardne práva 0660 pre používateľa a skupinu poolu. Nastavte listen.owner a listen.group tak, aby sa mohol pripojiť len webserver, nie každý lokálny používateľ.
Minimálne práva sú základný postoj, nie jednorazový projekt. Inventúru z tohto článku skontrolujte znova po každej prestavbe a po každom novom webe, pretože nové služby často prinášajú veľkorysé štandardné práva.
Záver: útočník zdedí, čo mu dovolíte
Least Privilege znie ako teória, no je to veľmi praktická otázka: čo môže urobiť ten, kto spúšťa kód ako používateľ webservera? Na serveri so shellom, záznamom sudo, vlastným crontabom a databázovým účtom so všetkými právami znie odpoveď: takmer všetko. Na obmedzenom serveri ide skôr o incident v jedinom webe, ktorý sa dá rozpoznať a vyčistiť.
Prechod nepotrebuje nový softvér, len starostlivú inventúru a postupné testy. Začnite bodmi, ktoré môžu pokaziť len máločo, teda shellom, sudo a kľúčmi SSH, a potom pokračujte k právam databázy a možnostiam systemd.
Ako konkrétne pomáha PHP SOS?
- Kontrola účtov: pre každý pool a webserver zachytíme používateľa, shell, záznamy sudo, úlohy cron, kľúče SSH a práva k databáze.
- Zníženie práv: odoberieme, čo sa nepotrebuje, a oddelíme účty pre nasadzovanie, prevádzku a údržbu.
- Obmedzenie služieb: ochranné možnosti systemd nastavujeme postupne a po každom kroku web testujeme.
- Udržať natrvalo: v rámci Hardeningu servera zdokumentujeme koncepciu práv pre budúce zmeny.
Časté otázky
Pod akým používateľom beží PHP na mojom serveri?
Závisí to od režimu prevádzky. Pri mod_php beží PHP ako používateľ Apache, napríklad www-data alebo apache. Pri PHP-FPM určuje používateľa každý pool pomocou user a group; hlavný proces zvyčajne beží ako root, workery ako používateľ poolu. Rýchlo to ukáže príkaz ps.
Potrebuje používateľ webservera prihlasovací shell?
Nie. Ani Nginx, ani Apache, ani PHP-FPM nepotrebujú pre tohto používateľa interaktívne prihlásenie. Shell ako /usr/sbin/nologin zabráni tomu, aby sa niekto prihlásil týmto účtom. Nasadzovanie (deployment) prebieha cez vlastného používateľa.
Prečo žiadne práva sudo pre www-data, ani pre jediný príkaz?
Pretože votrelecký kód zdedí presne tieto práva. Už zdanlivo neškodný príkaz môže po nesprávnom povolení viesť k právam root. Úlohy, ktoré potrebujú zvýšené práva, patria do oddelených služieb alebo postupov mimo webservera.
Pomáha to proti PHP2Shell?
Zraniteľnosť to neuzavrie, na to je potrebná aktualizácia PHP a reštart všetkých workerov. Minimálne práva však obmedzujú, čo môže útočník po úspešnom zneužití urobiť: meniť súbory, usadiť sa v systéme, dostať sa k iným webom.