Pe scurt: Un firewall pentru servere web permite la intrare doar TCP 80 și 443, la HTTP/3 suplimentar UDP 443, iar SSH doar din rețele cunoscute. Orice altceva este respins: bazele de date, cache-urile, PHP-FPM și interfețele de administrare nu aparțin internetului. Verificați mai întâi cu ss -tulpn ce ascultă, construiți apoi un set de reguli cu valoarea implicită „respinge” și testați rezultatul din exterior. Limitarea conexiunilor de ieșire restrânge suplimentar consecințele unei intruziuni.
Ușile uitate de lângă ușa de la intrare
La PHP2Shell, privirea s-a îndreptat către serverul web însuși, către porturile 80 și 443. Acestea trebuie să fie deschise, altfel nu există site. La inventarierile de după astfel de vulnerabilități iese însă adesea la iveală altceva: lângă ușa de la intrare mai stau deschise și alte uși. O bază de date ascultă pe toate interfețele de rețea, un pool PHP-FPM pe portul 9000, un serviciu de cache fără parolă, o interfață de administrare din faza de configurare.
Fiecare dintre aceste uși este o suprafață de atac proprie, cu vulnerabilități proprii. Un firewall care permite doar ce este necesar le închide cu puține reguli. Aceasta este una dintre cele mai eficiente măsuri la securizarea unui server propriu, așa cum o descrie și pagina Securizarea serverelor root și vServer pe cont propriu.
Ce aparține deschis, ce nu?
Principiul este o listă de permisiuni: totul este închis, iar doar serviciile eliberate conștient sunt accesibile. Prezentarea următoare ajută la încadrare.
| Serviciu | Port tipic | Accesibil din exterior? |
|---|---|---|
| HTTP și HTTPS | TCP 80, TCP 443 | da |
| HTTP/3 (QUIC) | UDP 443 | doar dacă este folosit |
| SSH | TCP 22 | doar din rețele cunoscute sau prin VPN |
| Panou de hosting | în funcție de produs | doar din rețele cunoscute |
| MySQL/MariaDB, PostgreSQL | TCP 3306, TCP 5432 | nu |
| Redis, Memcached | TCP 6379, TCP 11211 | nu |
| PHP-FPM | TCP 9000 sau socket Unix | nu, mai bine doar socket |
| Server de e-mail | TCP 25, 465, 587, 993 | doar dacă serverul primește sau furnizează e-mailuri |
Un serviciu care nu trebuie să fie accesibil din exterior ar trebui să asculte, în plus, doar pe 127.0.0.1 sau pe un socket Unix. Atunci rămâne inaccesibil chiar și în cazul unei defecțiuni a firewall-ului. Pentru accesurile de administrare se potrivesc permisiunile pe adrese IP sau un VPN; detalii în articolul Protejarea zonelor de administrare prin IP, VPN sau protecție suplimentară.
Pasul 1: stabiliți ce ascultă
Înainte să scrieți reguli, faceți-vă o imagine de ansamblu. Comenzile următoare doar citesc:
# Toate porturile TCP și UDP care ascultă, cu proces
sudo ss -tulpn
# Setul actual de reguli nftables
sudo nft list ruleset
# Starea ufw, dacă este folosit
sudo ufw status verbose
În ieșirea ss, fiți atenți la adresa dinaintea portului. 0.0.0.0 sau [::] înseamnă: serviciul ascultă pe toate interfețele. 127.0.0.1 înseamnă: doar local. Notați pentru fiecare serviciu dacă trebuie să fie accesibil din exterior. Această listă este totodată o parte din inventarul serverului dumneavoastră.
Firewall pentru servere web cu nftables
nftables este filtrul de pachete actual sub Linux. Setul de reguli următor se orientează după exemplul din wiki-ul oficial nftables și adaugă o permisiune pentru SSH doar dintr-o rețea de administrare. Adresele sunt exemple de documentație și trebuie înlocuite.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
set verwaltung_v4 {
type ipv4_addr
flags interval
elements = { 203.0.113.0/28 }
}
chain input {
type filter hook input priority 0; policy drop;
ct state vmap { established : accept, related : accept, invalid : drop }
iifname lo accept
# IPv6 are nevoie de descoperirea vecinilor
icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
icmp type echo-request limit rate 5/second accept
icmpv6 type echo-request limit rate 5/second accept
# Site
tcp dport { 80, 443 } accept
# doar la HTTP/3:
# udp dport 443 accept
# SSH doar din rețeaua de administrare
ip saddr @verwaltung_v4 tcp dport 22 accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
}
Verificați setul de reguli înainte de încărcare cu nft -c -f /etc/nftables.conf. Prima linie flush ruleset șterge toate regulile existente, inclusiv pe cele introduse de Docker sau Fail2ban. Pe serverele cu Docker sau cu alte servicii care își stabilesc reguli proprii, adaptați de aceea setul de reguli, în loc să îl înlocuiți în bloc. Cum colaborează Fail2ban cu firewall-ul se află la Configurarea Fail2ban pentru servere web.
Cine preferă varianta mai simplă folosește sub Ubuntu ufw. Importantă este ordinea: mai întâi permisiunea SSH, apoi activarea.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow proto tcp from 203.0.113.0/28 to any port 22
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
Modificați regulile firewall-ului pe servere la distanță doar cu o a doua cale de acces, de exemplu consola furnizorului dumneavoastră. O regulă SSH greșită vă blochează altfel pe dumneavoastră înșivă.
Conexiunile de ieșire: jumătatea subestimată
Majoritatea firewall-urilor permit la ieșire orice. Pentru un server web aceasta este generos. După o intruziune, atacatorii folosesc conexiunile de ieșire pentru a încărca unelte, a extrage date sau a primi comenzi. Procesele serverului web sau ale PHP care stabilesc conexiuni neașteptate sunt de aceea considerate un semnal de alarmă.
O limitare a conexiunilor de ieșire este mai laborioasă, pentru că fiecare conexiune legitimă trebuie cunoscută: sursele de pachete pentru actualizări, serviciile de plată, interfețele, trimiterea de e-mailuri, serverele de timp. O cale pragmatică este să jurnalizați mai întâi conexiunile de ieșire, să formați apoi o listă de permisiuni și abia după aceea să blocați. Cum verificați conexiunile existente descrie Verificarea conexiunilor de ieșire ale unui server; ce alte urme indică o intruziune se găsește la Am fost deja compromis?.
La final, testați din exterior, de pe un alt calculator și doar împotriva propriilor sisteme, ce porturi sunt, de fapt, accesibile. Abia acest test arată dacă Docker, firewall-ul furnizorului și regulile serverului dau împreună imaginea dorită.
Concluzie: puține reguli, efect mare
Un firewall pentru server web nu trebuie să fie complicat. Porturile web deschise, administrarea doar din rețele cunoscute, orice altceva respins: cu aceste reguli de bază, bazele de date, cache-urile și serviciile uitate dispar din internet. Este una dintre măsurile cu cel mai bun raport între efort și beneficiu.
Împotriva vulnerabilităților din serverul web sau din PHP însuși, firewall-ul nu ajută, pentru că tocmai aceste porturi trebuie să rămână deschise. Puterea lui constă în a menține mică restul suprafeței de atac și, printr-o limitare a conexiunilor de ieșire, în a restrânge consecințele unei intruziuni.
Decisivă este întreținerea. Orice serviciu nou, orice container și orice modificare la furnizor poate deplasa imaginea. Repetați de aceea verificarea din exterior după fiecare modificare mai mare și la intervale fixe, de exemplu o dată pe trimestru.
Cum ajută PHP SOS concret?
- Inventarierea stării existente: Inventariem toate serviciile care ascultă și verificăm din exterior ce este, de fapt, accesibil.
- Construirea setului de reguli: Întocmim o listă de permisiuni pentru conexiunile de intrare și, acolo unde are sens, de ieșire, coordonată cu Docker, Fail2ban și firewall-ul furnizorului.
- Trecere sigură: Aplicăm modificările cu o a doua cale de acces și cu un plan de rezervă.
- Documentare: Consemnăm porturile, permisiunile și motivele în cadrul securizării serverului.
Întrebări frecvente
De ce porturi are nevoie un server web?
Pentru vizitatori, de regulă doar TCP 80 și 443, la HTTP/3 suplimentar UDP 443. SSH și interfețele de administrare ar trebui să fie accesibile doar din rețele cunoscute sau prin VPN. Porturile bazelor de date, ale cache-ului și ale PHP-FPM nu aparțin internetului.
Mă protejează un firewall de PHP2Shell?
Nu. PHP2Shell este exploatată prin serverul web, deci prin exact porturile care trebuie să fie deschise. Firewall-ul micșorează însă restul suprafeței de atac, iar o limitare a conexiunilor de ieșire poate restrânge consecințele unei intruziuni.
De ce arată ufw porturi ca închise, deși sunt totuși accesibile?
Un caz cunoscut sunt containerele Docker: Docker introduce porturile publicate direct în regulile filtrului de pachete, pe lângă ufw. Verificați de aceea întotdeauna suplimentar porturile deschise din exterior.
Este suficient firewall-ul furnizorului meu de hosting?
Un firewall din față al furnizorului este un al doilea strat bun. El nu înlocuiește însă firewall-ul de pe server, pentru că nu acționează în caz de eroare în configurația furnizorului sau la conexiuni interne. Cel mai bine le folosiți pe amândouă, cu aceleași reguli de bază.