Ukratko: Korisnik web-poslužitelja pod kojim PHP radi trebao bi se prema načelu najmanjih ovlasti (Least Privilege) smjeti samo čitati ono što web-stranica treba i pisati samo tamo gdje odlaže podatke. Nema prijavnu ljusku, sudo prava, vlastite cron poslove ni SSH ključeve, a njegov račun za bazu podataka smije samo čitati i mijenjati podatke. Opcije systemd-a poput ProtectSystem i PrivateTmp dodatno ograničavaju PHP-FPM.
Pitanje nakon provale: što smije ovaj proces?
Kod PHP2Shella riječ je o izvršavanju zlonamjernog koda na daljinu bez prijave. Ako uspije, kod se ne izvršava u zraku, nego kao posve određeni korisnik: korisnik PHP procesa. Sve što taj korisnik smije, od tog trenutka smije i napadač.
Na mnogim je poslužiteljima to začuđujuće mnogo. Korisnik posjeduje cijeli programski kod, ima ljusku, može stvarati vlastite cron poslove, a račun baze podataka aplikacije ima sva prava na sve baze. Za napadača je to idealno polazište za trajno uhodavanje.
Kako ispravno dodijeliti datoteke i mape, opisuje vodič Prava datoteka na web-poslužitelju. Ovaj članak razmatra sam račun: prijavu, posebna prava, planirane zadatke, bazu podataka i granice koje postavlja systemd.
Popis stanja: tko je korisnik web-poslužitelja?
Najprije utvrdite koji su korisnici uopće uključeni. Kod PHP-FPM-a svaki pool pomoću user i group određuje pod kojim korisnikom rade njegovi workeri. Kod mod_php-a PHP radi kao Apache korisnik. Kako glavni proces i workeri surađuju u PHP-FPM-u, objašnjava članak PHP-FPM objašnjen: upravitelj procesa, poolovi i workeri. Sljedeće naredbe samo čitaju:
# Pod kojim korisnicima rade web-poslužitelj i PHP?
ps -eo user,group,cmd | grep -E "[p]hp-fpm|[n]ginx|[a]pache2|[h]ttpd" | sort | uniq -c
# Podaci o računu: matični direktorij i ljuska (prilagodite korisnika)
getent passwd www-data
# Ima li korisnik sudo prava?
sudo -l -U www-data
# Vlastiti cron poslovi?
sudo crontab -l -u www-data
# SSH ključevi u matičnom direktoriju (na Debianu/Ubuntuu to je /var/www)
sudo ls -la /var/www/.ssh 2>/dev/null
Zabilježite rezultate za svakog korisnika poola. Ako sve web-stranice rade pod istim korisnikom, to je prva točka na popisu; kako to razdvojiti, opisuje članak Izolirati PHP-FPM poolove po web-stranici.
Prava korisnika web-poslužitelja: što taj račun ne treba
Sljedeći pregled pokazuje što korisnik web-poslužitelja tipično ne treba i kako mu to oduzeti.
| Pravo | Zašto je opasno | Preporuka |
|---|---|---|
| Prijavna ljuska | moguća prijava i interaktivno korištenje | ljuska /usr/sbin/nologin |
| sudo unosi | put do root prava | nema unosa, ni za pojedinačne naredbe |
| vlastiti crontab | trajna stražnja vrata koja preživljavaju svako ponovno pokretanje | nema ga, ograničiti pomoću /etc/cron.allow |
| SSH ključevi | prijava izvana | nema authorized_keys |
| Vlasništvo nad programskim kodom | kod se može mijenjati | vlasnik je korisnik za isporuku (deploy) |
| Prava pisanja izvan mapa s podacima | odlaganje zlonamjernog koda | samo uploads, cache, temp |
| puna prava baze podataka | baze drugih aplikacija, pristup datotekama preko baze | samo vlastita baza, samo prava nad podacima |
Ljusku postavljate naredbom usermod -s /usr/sbin/nologin www-data. Za cron vrijedi: ako postoji /etc/cron.allow, vlastite cron poslove smiju stvarati samo tamo navedeni korisnici. Novostvoreni cron poslovi ili nepoznati SSH ključevi tipičan su znak da se netko učvrstio. Osobito jasan znak upozorenja opisuje članak Znak upozorenja: web-poslužitelj pokreće ljusku.
Baza podataka: ograničiti prava na nužno
Račun baze podataka web-stranice zapravo je drugi korisnik web-poslužitelja. Njegovi pristupni podaci nalaze se u konfiguracijskoj datoteci aplikacije i ubačeni ih kod može čitati. Zato smije samo ono što aplikacija treba u radu.
-- Primjer MySQL/MariaDB: vlastiti račun za svaku web-stranicu, samo prava nad podacima
CREATE USER 'seite1'@'localhost' IDENTIFIED BY 'hier-ein-langes-Zufallspasswort';
GRANT SELECT, INSERT, UPDATE, DELETE ON seite1.* TO 'seite1'@'localhost';
-- Provjeriti prava
SHOW GRANTS FOR 'seite1'@'localhost';
Prava poput FILE, SUPER ili GRANT OPTION te pristup na *.* aplikacijski račun ne treba. Mnogi CMS-ovi za ažuriranja dodatno trebaju CREATE, ALTER, INDEX i DROP. Čišće je imati zaseban račun za ažuriranja i migracije koji se koristi samo tijekom održavanja. Zahtjeve provjerite u dokumentaciji proizvođača.
PHP-FPM dodatno ograničiti pomoću systemd-a
systemd može ograničiti pogled usluge na sustav. Za PHP-FPM osobito su prikladne neke opcije iz systemd dokumentacije. One djeluju i na glavni proces koji se pokreće kao root.
# sudo systemctl edit php8.3-fpm
[Service]
# /usr, /boot i /etc zaštićeni od pisanja
ProtectSystem=full
# /home, /root i /run/user nevidljivi
ProtectHome=true
# vlastiti /tmp i /var/tmp samo za ovu uslugu
PrivateTmp=true
# nema proširenja prava putem setuid-a ili capabilities datoteka
NoNewPrivileges=true
Ove opcije testirajte prije produkcijske primjene. Ako se web-stranice nalaze pod /home, ProtectHome=true sprječava pristup. NoNewPrivileges=true može smetati programima koje PHP poziva i koji pri pokretanju mijenjaju svoja grupna prava, primjerice nekim lokalnim programima za e-poštu za PHP funkciju mail(). Zato postupajte u koracima:
- Dodati jednu opciju, ponovno pokrenuti uslugu, provjeriti
systemctl status php8.3-fpm. - Testirati ključne funkcije web-stranice: prijavu, obrasce, slanje e-pošte, uploade, cron poslove aplikacije.
- Analizirati zapisnik pogrešaka PHP-FPM-a i aplikacije.
- Tek zatim dodati sljedeću opciju.
Za kraj, socket: prema PHP priručniku prema zadanoj postavci dobiva prava 0660 za korisnika i grupu poola. Postavite listen.owner i listen.group tako da se može povezati samo web-poslužitelj, a ne svaki lokalni korisnik.
Minimalna prava stav su, a ne jednokratni projekt. Popis stanja iz ovog članka ponovno provjerite nakon svake preinake i svake nove web-stranice, jer nove usluge često dolaze s velikodušnim zadanim pravima.
Zaključak: napadač nasljeđuje ono što dopustite
Najmanje ovlasti zvuči kao teorija, ali je vrlo praktično pitanje: što može učiniti netko tko izvršava kod kao korisnik web-poslužitelja? Na poslužitelju s ljuskom, sudo unosom, vlastitim crontabom i računom baze podataka sa svim pravima odgovor glasi: gotovo sve. Na ograničenom poslužitelju ostaje češće kod incidenta na pojedinačnoj web-stranici, koji se može prepoznati i sanirati.
Prelazak ne traži novi softver, nego pažljiv popis stanja i postupna testiranja. Počnite točkama koje gotovo ništa ne mogu pokvariti, dakle ljuskom, sudo-om i SSH ključevima, a zatim prijeđite na prava baze podataka i opcije systemd-a.
Kako PHP SOS konkretno pomaže?
- Provjera računa: Za svaki pool i web-poslužitelj bilježimo korisnika, ljusku, sudo unose, cron poslove, SSH ključeve i prava baze podataka.
- Smanjenje prava: Oduzimamo ono što se ne koristi i razdvajamo račune za isporuku, rad i održavanje.
- Ograničavanje usluga: Zaštitne opcije systemd-a postavljamo postupno i nakon svakog koraka testiramo web-stranicu.
- Trajno održavanje: U okviru ojačavanja poslužitelja dokumentiramo koncept prava za buduće promjene.
Česta pitanja
Pod kojim korisnikom PHP radi na mojem poslužitelju?
Ovisi o načinu rada. Kod mod_php-a PHP radi kao Apache korisnik, primjerice www-data ili apache. Kod PHP-FPM-a svaki pool određuje svojeg korisnika pomoću user i group; glavni proces obično radi kao root, a workeri kao korisnik poola. Naredba ps to brzo prikazuje.
Treba li korisniku web-poslužitelja prijavna ljuska?
Ne. Ni Nginx ni Apache ni PHP-FPM ne trebaju interaktivnu prijavu za tog korisnika. Ljuska poput /usr/sbin/nologin sprječava da se netko prijavi tim računom. Isporuke (deployment) idu preko zasebnog korisnika.
Zašto www-data nema sudo prava, ni za jednu jedinu naredbu?
Zato što ubačeni kod nasljeđuje upravo ta prava. Već naizgled bezazlena naredba, ako je pogrešno odobrena, može dovesti do root prava. Zadaci koji traže povišena prava pripadaju u odvojene usluge ili procese izvan web-poslužitelja.
Pomaže li to protiv PHP2Shella?
Ne zatvara ranjivost, za to su potrebni PHP update i ponovno pokretanje svih workera. No minimalna prava ograničavaju što napadač može učiniti nakon uspješnog iskorištavanja: mijenjati datoteke, učvrstiti se, doprijeti do drugih web-stranica.