Stručne: Ak chcete Nginx pre PHP bezpečne nakonfigurovať, odovzdávajte do PHP-FPM len skripty, ktoré skutočne existujú, pri aplikáciách s front-controllerom dokonca len index.php. K tomu patria zablokované dotfiles ako .git a .env, štandardný server pre neznáme názvy hostiteľov, vhodné limity veľkosti a security.limit_extensions = .php v poole. Pred zraniteľnosťami v samotnom PHP to nechráni, obmedzuje však, čo je po chybe vykonateľné.
Najnebezpečnejšie riadky sú v lokácii PHP
Od PHP2Shell mnohé tímy kontrolujú svoje verzie PHP-FPM a pooly, ako opisuje stránka Zabezpečenie Nginx s PHP-FPM, a po aktualizácii reštartujú všetkých workerov. Druhý pohľad patrí samotnej konfigurácii Nginx. Tam sa rozhoduje, ktoré súbory sa vôbec vykonajú ako PHP.
V mnohých konfiguráciách je blok, ktorý každú požiadavku na .php odovzdá PHP-FPM, bez ohľadu na to, kde súbor leží. Ak votknutý súbor PHP pristane v priečinku s uploadmi, server ho vykoná. Z chyby v súboroch sa tak stane zadné vrátko.
Tento príspevok sa sústreďuje na stranu Nginx: ktoré direktívy rozhodujú, ako pôsobí poradie blokov location a ako výsledok otestovať.
Ako Nginx rozhoduje, ktorý blok sa uplatní
Kto chce Nginx pre PHP bezpečne nakonfigurovať, musí poznať výber blokov location. Podľa dokumentácie Nginx prebieha takto:
- Presná zhoda s
location =okamžite ukončí hľadanie. - Medzi lokáciami s predponou sa zapamätá najdlhšia vyhovujúca. Ak má
^~, regulárne výrazy sa už nekontrolujú. - Inak sa regulárne výrazy (
~,~*) kontrolujú v poradí konfiguračného súboru; vyhráva prvá zhoda. - Ak nevyhovie žiaden regulárny výraz, platí zapamätaná lokácia s predponou.
Z toho vyplývajú dve praktické pravidlá. Blokovanie PHP v priečinkoch s uploadmi sa musí buď zriadiť ako predpona ^~, alebo stáť ako regulárny výraz pred všeobecným blokom PHP. A bežná lokácia s predponou ako location /uploads/ nechráni, pretože ju regulárny výraz pre .php prebije.
Bezpečná základná konfigurácia
Nasledujúci príklad ukazuje blok server pre aplikáciu s front-controllerom, aká je bežná pri Laravel, Symfony, Shopware 6 alebo mnohých vlastných vývojoch. Cesty, socket a certifikáty si prispôsobte.
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;
# Povoliť Let's Encrypt a ďalšie známe cesty
location ^~ /.well-known/ {
try_files $uri =404;
}
# Zablokovať skryté súbory a priečinky (.git, .env, .htaccess)
location ~ /\. {
deny all;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# Do PHP-FPM sa odovzdáva len 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;
}
# Každý iný súbor PHP sa nevykoná
location ~ \.php$ {
return 404;
}
}
$realpath_root rozlišuje symbolické odkazy. To je pri nasadeniach so striedavým symlinkom na aktuálne vydanie dôležité, aby PHP-FPM a OPcache videli správnu cestu. Majte navyše na pamäti: podľa dokumentácie Nginx sa direktívy fastcgi_param dedia z vyšších úrovní len vtedy, ak na aktuálnej úrovni nie sú vlastné. Preto patrí include fastcgi_params; do toho istého bloku.
Klasické CMS ako WordPress, TYPO3 alebo Contao majú viacero vstupných bodov. Tam nahradíte blok front-controllera všeobecnou lokáciou PHP, ktorá odovzdáva len existujúce súbory (try_files $uri =404;), a zablokujete vykonávanie vo všetkých zapisovateľných priečinkoch. Ako sa to darí, uvádza Zákaz vykonávania PHP v priečinkoch s uploadmi.
Druhé zabezpečenie v PHP-FPM
Nginx rozhoduje, čo sa odovzdá ďalej, PHP-FPM rozhoduje, čo vykoná. Podľa príručky PHP PHP-FPM štandardne vykonáva súbory s .php a .phar a samo odporúča obmedziť to na .php. To zachytí chyby konfigurácie vo webovom serveri.
; v poole, napr. /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 by mal byť dostupný len pre Nginx. Porty FPM v sieti, napríklad 9000, sa nesmú otvárať smerom von. Ako server celkovo ukazuje len potrebné porty, opisuje Firewall pre webové servery: otvárať len potrebné porty.
Neznáme názvy hostiteľov a ďalšie nastavenia
Bez vlastného štandardného servera Nginx odpovedá na požiadavky na neznáme názvy hostiteľov prvým vhodným blokom server. Automatizované skeny, ktoré oslovujú len adresu IP, potom pristanú priamo vo vašej aplikácii. Vlastný štandardný server také požiadavky ukončí bez odpovede.
server {
listen 80 default_server;
listen 443 ssl default_server;
server_name _;
ssl_reject_handshake on;
return 444;
}
Ďalšie osvedčené body:
| Nastavenie | Odporúčanie | Účel |
|---|---|---|
server_tokens |
off |
žiadne číslo verzie v hlavičke a na chybových stránkach |
client_max_body_size |
zodpovedajúce post_max_size |
veľké požiadavky odmietať včas |
autoindex |
vypnuté (štandard) | žiadne zoznamy adresárov |
fastcgi_hide_header |
X-Powered-By |
žiadna verzia PHP smerom von |
| Stavové stránky | pm.status_path len interne |
žiadne prevádzkové údaje verejne |
| Záložné súbory | .sql, .zip, .bak vo webovom koreni zablokovať alebo odstrániť |
žiadne sťahovanie databáz |
Viac k údajom o verzii je v príspevku expose_php a hlavičky Server.
Ďalšie nastavenie sa týka povolených metód HTTP. Väčšina webov potrebuje len GET, HEAD a POST. Pomocou limit_except sa dajú iné metódy v lokácii odmietnuť; podľa dokumentácie Nginx povolenie GET automaticky povoľuje aj HEAD. Vopred skontrolujte, či rozhrania vašej aplikácie nepoužívajú napríklad PUT alebo DELETE, pretože REST API to často robia.
Testovať skôr, než znova načítate
Každú zmenu najprv skontrolujte pomocou nginx -t a Nginx znova načítajte až potom. Následne otestujte správanie zvonka bežnými požiadavkami na vlastnú doménu:
sudo nginx -t && sudo systemctl reload nginx
# Očakáva sa: 403 alebo 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
# Očakáva sa: 404, pretože sa vykonáva len front-controller
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# Ktoré bloky odovzdávajú do PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"
Pred každou väčšou zmenou si so dátumom zálohujte úplný výstup nginx -T. Obsahuje celú účinnú konfiguráciu vrátane všetkých vložených súborov. Ak sa po zmene niečo pokazí, porovnanie okamžite ukáže, čo sa líši. Pri najbližšej kritickej zraniteľnosti tak máte navyše spoľahlivý základ pre inventúru, bez toho, aby ste súbory museli zbierať.
Konfiguráciu meňte najprv v testovacom prostredí alebo na kópii bloku server. Zabudnutý vstupný bod, napríklad platobný callback, sa inak prejaví až vtedy, keď prestanú chodiť objednávky.
Ako konkrétne pomáha PHP SOS?
- Prečítať konfiguráciu: vyhodnotíme celú konfiguráciu Nginx pomocou
nginx -Ta každé odovzdanie do PHP priradíme jeho webu a poolu. - Určiť vstupné body: spolu s vašimi vývojármi určíme, ktoré skripty sa musia vykonávať, a zvyšok zablokujeme.
- Zaviesť a otestovať: upravíme bloky server a pooly, skontrolujeme pomocou
nginx -ta otestujeme formuláre, platobné cesty a uploady. - Zabezpečiť trvalo: konfigurácia sa stane súčasťou nášho sprísnenia servera a dokumentácie vášho servera.
Časté otázky
Musí sa Nginx po aktualizácii PHP reštartovať?
Pre záplatu PHP nie, pretože Nginx neobsahuje PHP. Reštartovať sa musia všetky služby PHP-FPM. Ak pritom meníte aj konfiguráciu Nginx, skontrolujte ju vopred pomocou nginx -t a potom Nginx znova načítajte.
Prečo odovzdávať PHP len index.php?
Mnohé moderné aplikácie majú jediný vstupný bod, front-controller. Ak sa PHP-FPM odovzdáva len tento súbor, votknutý súbor PHP na inom mieste sa cez prehliadač vykonať nedá. Pri systémoch s mnohými vstupnými bodmi tento vzor nie je možný.
Čo prináša security.limit_extensions v PHP-FPM?
Nastavenie určuje, ktoré prípony súborov PHP-FPM vykoná ako skript. Podľa príručky PHP je štandard .php .phar; odporúča sa obmedziť na .php. To zachytí chyby v konfigurácii webového servera, nenahrádza ju však.
Sú pravidlá Nginx ochranou proti PHP2Shell?
Nie. PHP2Shell sídli v interpreteri PHP a uzavrie sa len aktualizáciou na opravenú verziu a reštartom všetkých workerov. Bezpečná konfigurácia Nginx zmenšuje útočnú plochu a obmedzuje škodu po vlámaní.