Na kratko: Za varno konfiguracijo Nginx za PHP na PHP-FPM predajte samo skripte, ki res obstajajo, pri aplikacijah s front controllerjem celo samo index.php. K temu sodijo zaprti dotfile, kot sta .git in .env, privzeti strežnik za neznana imena gostiteljev, ustrezne meje velikosti in security.limit_extensions = .php v poolu. To ne ščiti pred ranljivostmi v samem PHP, omeji pa, kaj je po napaki izvršljivo.
Najnevarnejše vrstice so v lokaciji PHP
Od PHP2Shell številne ekipe preverjajo svoje različice PHP-FPM in poole, kot opisuje stran Zavarovanje Nginx s PHP-FPM, ter po posodobitvi znova zaženejo vse delavce. Drugi pogled velja sami konfiguraciji Nginx. Tam se odloči, katere datoteke se sploh izvedejo kot PHP.
V številnih konfiguracijah je blok, ki vsako zahtevo za .php posreduje na PHP-FPM, ne glede na to, kje datoteka leži. Če vnesena datoteka PHP pristane v mapi za nalaganje, jo strežnik izvede. Iz napake z datoteko tako nastanejo stranska vrata.
Ta prispevek se osredotoča na stran Nginx: katere direktive štejejo, kako deluje vrstni red blokov location in kako rezultat preizkusite.
Kako Nginx odloči, kateri blok velja
Kdor želi Nginx za PHP varno konfigurirati, mora poznati izbiro blokov location. Po dokumentaciji Nginx poteka takole:
- Natančen zadetek z
location =takoj konča iskanje. - Med predponskimi lokacijami se zapomni najdaljša ustrezna. Če nosi
^~, se regularni izrazi ne preverjajo več. - Sicer se regularni izrazi (
~,~*) preverjajo v vrstnem redu konfiguracijske datoteke; prvi zadetek zmaga. - Če noben regularni izraz ne ustreza, velja zapomnjena predponska lokacija.
Iz tega izhajata dve praktični pravili. Zapora za PHP v mapah za nalaganje mora biti ali predpona ^~ ali regularni izraz pred splošnim blokom PHP. In navadna predponska lokacija, kot je location /uploads/, ne ščiti, ker jo regularni izraz za .php preglasi.
Varna osnovna konfiguracija
Naslednji primer prikazuje blok strežnika za aplikacijo s front controllerjem, kot je običajna pri Laravel, Symfony, Shopware 6 ali številnih lastnih razvojih. Poti, socket in certifikate prilagodite.
server {
listen 443 ssl;
server_name www.example.de;
root /var/www/seite1/public;
index index.php;
ssl_certificate /etc/ssl/seite1/fullchain.pem;
ssl_certificate_key /etc/ssl/seite1/privkey.pem;
server_tokens off;
client_max_body_size 32m;
# Dovoli Let's Encrypt in druge znane poti
location ^~ /.well-known/ {
try_files $uri =404;
}
# Zaprite skrite datoteke in mape (.git, .env, .htaccess)
location ~ /\. {
deny all;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# Na PHP-FPM se preda samo front controller
location = /index.php {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_hide_header X-Powered-By;
fastcgi_pass unix:/run/php/seite1.sock;
}
# Nobena druga datoteka PHP se ne izvede
location ~ \.php$ {
return 404;
}
}
$realpath_root razreši simbolne povezave. To je pomembno pri namestitvah s spreminjajočo se simbolno povezavo na aktualno izdajo, da PHP-FPM in OPcache vidita pravo pot. Upoštevajte tudi: po dokumentaciji Nginx se direktive fastcgi_param z višjih ravni dedujejo le, če na trenutni ravni ni lastnih. Zato include fastcgi_params; sodi v isti blok.
Klasični CMS, kot so WordPress, TYPO3 ali Contao, imajo več vstopnih točk. Tam blok front controllerja zamenjate s splošno lokacijo PHP, ki predaja samo obstoječe datoteke (try_files $uri =404;), in izvajanje zaprete v vseh zapisljivih mapah. Kako to uspe, piše pod Prepoved izvajanja PHP v mapah za nalaganje.
Drugo zaščito v PHP-FPM
Nginx odloča, kaj se posreduje, PHP-FPM odloča, kaj izvede. Po priročniku PHP PHP-FPM privzeto izvaja datoteke s .php in .phar ter sam priporoča omejitev na .php. To ujame napake v konfiguraciji spletnega strežnika.
; v poolu, npr. /etc/php/8.3/fpm/pool.d/seite1.conf
security.limit_extensions = .php
listen = /run/php/seite1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
Socket naj bo dosegljiv samo za Nginx. Vrat FPM v omrežju, na primer 9000, ne odpirajte navzven. Kako strežnik kot celota kaže samo potrebna vrata, opisuje Požarni zid za spletne strežnike: odprite samo potrebna vrata.
Neznana imena gostiteljev in druge nastavitve
Brez lastnega privzetega strežnika Nginx zahteve za neznana imena gostiteljev odgovori s prvim ustreznim blokom strežnika. Samodejna skeniranja, ki nagovarjajo samo naslov IP, potem pristanejo neposredno v vaši aplikaciji. Lasten privzeti strežnik take zahteve konča brez odgovora.
server {
listen 80 default_server;
listen 443 ssl default_server;
server_name _;
ssl_reject_handshake on;
return 444;
}
Nadaljnje točke, ki so se obnesle:
| Nastavitev | Priporočilo | Namen |
|---|---|---|
server_tokens |
off |
brez številke različice v glavah in na straneh z napakami |
client_max_body_size |
usklajeno s post_max_size |
velike zahteve zavrniti zgodaj |
autoindex |
izklopljeno (privzeto) | brez seznamov map |
fastcgi_hide_header |
X-Powered-By |
brez različice PHP navzven |
| Statusne strani | pm.status_path samo notranje |
brez javnih podatkov o delovanju |
| Datoteke varnostnih kopij | .sql, .zip, .bak v spletnem korenu zapreti ali odstraniti |
brez prenosa zbirk podatkov |
Več o podatkih o različicah piše v prispevku expose_php in glave Server.
Nadaljnja nastavitev zadeva dovoljene metode HTTP. Večina spletnih strani potrebuje samo GET, HEAD in POST. Z limit_except je mogoče druge metode v lokaciji zavrniti; po dokumentaciji Nginx dovoljenje za GET samodejno dovoli tudi HEAD. Prej preverite, ali vmesniki vaše aplikacije uporabljajo na primer PUT ali DELETE, saj to REST API pogosto počnejo.
Preizkus, preden znova naložite
Vsako spremembo najprej preverite z nginx -t in šele nato znova naložite Nginx. Nato obnašanje od zunaj preizkusite z običajnimi zahtevami na svojo domeno:
sudo nginx -t && sudo systemctl reload nginx
# Pričakovano: 403 ali 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/HEAD
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env
# Pričakovano: 404, ker se izvede samo front controller
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# Kateri bloki predajajo na PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"
Pred vsako večjo spremembo zavarujte celoten izpis nginx -T z datumom. Vsebuje celotno veljavno konfiguracijo, vključno z vsemi vključenimi datotekami. Če se po spremembi kaj zalomi, primerjava takoj pokaže, kaj se razlikuje. Ob naslednji kritični ranljivosti imate poleg tega zanesljivo podlago za popis stanja, ne da bi morali datoteke najprej zbirati.
Konfiguracijo najprej spremenite v testnem okolju ali na kopiji bloka strežnika. Pozabljena vstopna točka, na primer povratni klic plačila, se sicer pokaže šele, ko naročila izostanejo.
Kako PHP SOS pomaga konkretno?
- Branje konfiguracije: celotno konfiguracijo Nginx ovrednotimo z
nginx -Tin vsako predajo PHP umestimo v njeno spletno stran in pool. - Določitev vstopnih točk: skupaj z vašimi razvijalci določimo, kateri skripti se morajo izvajati, in zapremo preostale.
- Izvedba in preizkus: prilagodimo bloke strežnika in poole, preverimo z
nginx -tter preizkusimo obrazce, plačilne poti in nalaganja. - Trajna zaščita: konfiguracija postane del našega utrjevanja strežnikov in dokumentacije vašega strežnika.
Pogosta vprašanja
Ali je treba Nginx po posodobitvi PHP znova zagnati?
Za popravek PHP ne, ker Nginx ne vsebuje PHP. Znova je treba zagnati vse storitve PHP-FPM. Če pri tem spreminjate tudi konfiguracijo Nginx, jo prej preverite z nginx -t in nato Nginx znova naložite.
Zakaj na PHP posredovati samo index.php?
Številne sodobne aplikacije imajo eno samo vstopno točko, front controller. Če se na PHP-FPM preda samo ta datoteka, vnesene datoteke PHP drugje ni mogoče izvesti prek brskalnika. Pri sistemih z veliko vstopnimi točkami ta vzorec ni mogoč.
Kaj prinese security.limit_extensions v PHP-FPM?
Nastavitev določa, katere končnice datotek PHP-FPM izvede kot skript. Po priročniku PHP je privzeto .php .phar; priporočena je omejitev na .php. To ujame napake v konfiguraciji spletnega strežnika, vendar je ne nadomešča.
Ali so pravila Nginx zaščita pred PHP2Shell?
Ne. PHP2Shell je v interpreterju PHP in se zapre samo s posodobitvijo na popravljeno različico ter ponovnim zagonom vseh delavcev. Varna konfiguracija Nginx zmanjša napadalno površino in omeji škodo po vdoru.