Situația actuală: PHP2Shell. Două vulnerabilități critice PHP (CVSS 9.2) permit cod malițios fără autentificare. Patchuri din 21.10.2026.Ce este de făcut acum →

Configurarea sigură a Nginx pentru PHP

Cele mai multe vulnerabilități din configurațiile Nginx pentru PHP nu se află în Nginx, ci în câteva rânduri din location-ul PHP. Cum configurați transmiterea către PHP-FPM astfel încât să fie executate doar scripturile dorite.

Stadiu 6 min de cititSecurizare și configurare

Pe scurt: Pentru a configura sigur Nginx pentru PHP, transmiteți către PHP-FPM doar scripturile care există cu adevărat, iar la aplicațiile cu front-controller chiar doar index.php. Se adaugă dotfile-uri blocate, precum .git și .env, un server implicit pentru nume de gazdă necunoscute, limite de dimensiune potrivite și security.limit_extensions = .php în pool. Asta nu protejează de vulnerabilități din PHP însuși, dar limitează ce poate fi executat după o eroare.

Cele mai periculoase rânduri se află în location-ul PHP

De la PHP2Shell, multe echipe își verifică versiunile PHP-FPM și pool-urile, așa cum descrie pagina Securizarea Nginx cu PHP-FPM, și repornesc toți workerii după actualizare. O a doua privire se îndreaptă către configurația Nginx însăși. Acolo se decide ce fișiere sunt executate, de fapt, ca PHP.

În multe configurații există un bloc care transmite către PHP-FPM orice cerere către .php, indiferent unde se află fișierul. Dacă un fișier PHP introdus ajunge într-un dosar de upload, serverul îl execută. Dintr-o eroare de fișier devine astfel o ușă dosnică.

Acest articol se concentrează pe partea Nginx: ce directive contează, cum acționează ordinea blocurilor location și cum testați rezultatul.

Cum decide Nginx ce bloc se aplică

Cine vrea să configureze sigur Nginx pentru PHP trebuie să cunoască alegerea blocurilor location. Potrivit documentației Nginx, aceasta decurge astfel:

  1. O potrivire exactă cu location = încheie imediat căutarea.
  2. Dintre location-urile cu prefix este reținut cel mai lung care se potrivește. Dacă poartă ^~, nu mai sunt verificate expresii regulate.
  3. Altfel, expresiile regulate (~, ~*) sunt verificate în ordinea din fișierul de configurare; prima potrivire câștigă.
  4. Dacă nicio expresie regulată nu se potrivește, se aplică location-ul cu prefix reținut.

De aici rezultă două reguli practice. O blocare a PHP în dosarele de upload trebuie fie creată ca prefix ^~, fie pusă ca expresie regulată înaintea blocului PHP general. Iar un location obișnuit cu prefix, precum location /uploads/, nu protejează, deoarece expresia regulată pentru .php îl depășește.

O configurație de bază sigură

Exemplul următor arată un bloc server pentru o aplicație cu front-controller, așa cum este uzual la Laravel, Symfony, Shopware 6 sau multe dezvoltări proprii. Căile, socketul și certificatele le adaptați.

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;

    # Permite Let's Encrypt și alte căi cunoscute
    location ^~ /.well-known/ {
        try_files $uri =404;
    }

    # Blochează fișierele și dosarele ascunse (.git, .env, .htaccess)
    location ~ /\. {
        deny all;
    }

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # Doar front-controller-ul este transmis către PHP-FPM
    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;
    }

    # Orice alt fișier PHP nu este executat
    location ~ \.php$ {
        return 404;
    }
}

$realpath_root rezolvă legăturile simbolice. Acest lucru este important la deploymenturile cu legătură simbolică schimbătoare către release-ul curent, pentru ca PHP-FPM și OPcache să vadă calea corectă. Rețineți și: potrivit documentației Nginx, directivele fastcgi_param sunt moștenite de la nivelurile superioare doar dacă la nivelul curent nu există directive proprii. De aceea include fastcgi_params; aparține aceluiași bloc.

CMS-urile clasice, precum WordPress, TYPO3 sau Contao, au mai multe puncte de intrare. Acolo înlocuiți blocul front-controller cu un location PHP general, care transmite doar fișierele existente (try_files $uri =404;), și blocați execuția în toate dosarele scriibile. Cum reușiți acest lucru găsiți la Interzicerea execuției PHP în dosarele de upload.

A doua securizare, în PHP-FPM

Nginx decide ce este transmis mai departe, PHP-FPM decide ce execută. Potrivit manualului PHP, PHP-FPM execută implicit fișiere cu .php și .phar și recomandă el însuși limitarea la .php. Aceasta prinde erorile de configurare din serverul web.

; în pool, de ex. /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

Socketul ar trebui să fie accesibil doar pentru Nginx. Porturile FPM din rețea, de exemplu 9000, nu trebuie deschise spre exterior. Cum arată serverul în ansamblu doar porturile necesare descrie Firewall pentru servere web: deschideți doar porturile necesare.

Nume de gazdă necunoscute și alte șuruburi de reglaj

Fără un server implicit propriu, Nginx răspunde cererilor către nume de gazdă necunoscute cu primul bloc server potrivit. Scanările automate care se adresează doar adresei IP ajung atunci direct în aplicația dumneavoastră. Un server implicit propriu încheie astfel de cereri fără răspuns.

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_reject_handshake on;
    return 444;
}

Alte puncte care s-au dovedit utile:

Șurub de reglaj Recomandare Scop
server_tokens off fără număr de versiune în antet și pe paginile de eroare
client_max_body_size potrivit cu post_max_size respingerea timpurie a cererilor mari
autoindex oprit (implicit) fără liste de directoare
fastcgi_hide_header X-Powered-By fără versiune PHP spre exterior
Pagini de stare pm.status_path doar intern fără date de operare publice
Fișiere de backup blocați sau eliminați .sql, .zip, .bak din webroot fără descărcarea bazelor de date

Mai multe despre indicațiile de versiune se găsesc în articolul expose_php și antetele Server.

Un alt șurub de reglaj privește metodele HTTP permise. Majoritatea site-urilor au nevoie doar de GET, HEAD și POST. Cu limit_except, alte metode pot fi respinse într-un location; potrivit documentației Nginx, permiterea GET permite automat și HEAD. Verificați înainte dacă interfețele aplicației dumneavoastră folosesc, de exemplu, PUT sau DELETE, căci API-urile REST o fac frecvent.

Testați înainte de a reîncărca

Fiecare modificare o verificați mai întâi cu nginx -t și abia apoi reîncărcați Nginx. Apoi testați comportamentul din exterior cu cereri normale către propriul domeniu:

sudo nginx -t && sudo systemctl reload nginx
# Așteptat: 403 sau 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
# Așteptat: 404, deoarece este executat doar front-controller-ul
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# Ce blocuri transmit către PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"

Înainte de fiecare modificare mai mare, salvați cu dată ieșirea completă a nginx -T. Ea conține întreaga configurație efectivă, inclusiv toate fișierele incluse. Dacă după o modificare ceva merge prost, comparația arată imediat ce diferă. La următoarea vulnerabilitate critică aveți astfel și o bază fiabilă pentru inventariere, fără să fie nevoie să adunați mai întâi fișiere.

Sfat

Modificați configurația mai întâi într-un mediu de test sau pe o copie a blocului server. Un punct de intrare uitat, de exemplu un callback de plată, iese altfel la iveală abia când comenzile nu mai vin.

Cum ajută PHP SOS concret?

  • Citirea configurației: Evaluăm întreaga configurație Nginx cu nginx -T și atribuim fiecare transmitere către PHP site-ului și pool-ului său.
  • Stabilirea punctelor de intrare: Împreună cu dezvoltatorii dumneavoastră stabilim ce scripturi trebuie executate și blocăm restul.
  • Implementare și testare: Adaptăm blocurile server și pool-urile, verificăm cu nginx -t și testăm formularele, căile de plată și încărcările.
  • Securizare durabilă: Configurația devine parte a securizării serverului și a documentației serverului dumneavoastră.

Întrebări frecvente

Trebuie repornit Nginx după o actualizare PHP?

Nu pentru patchul PHP, deoarece Nginx nu conține PHP. Trebuie repornite toate serviciile PHP-FPM. Dacă modificați în același timp configurația Nginx, verificați-o înainte cu nginx -t și reîncărcați apoi Nginx.

De ce să transmit către PHP doar index.php?

Multe aplicații moderne au un singur punct de intrare, front-controller-ul. Dacă doar acest fișier este transmis către PHP-FPM, un fișier PHP introdus în alt loc nu poate fi executat prin browser. La sistemele cu multe puncte de intrare, acest tipar nu este posibil.

Ce aduce security.limit_extensions în PHP-FPM?

Setarea stabilește ce extensii de fișier execută PHP-FPM ca script. Potrivit manualului PHP, valoarea implicită este .php .phar; se recomandă limitarea la .php. Aceasta prinde erorile din configurația serverului web, dar nu o înlocuiește.

Sunt regulile Nginx o protecție împotriva PHP2Shell?

Nu. PHP2Shell se află în interpretorul PHP și este închisă doar prin actualizarea la o versiune corectată și repornirea tuturor workerilor. O configurație Nginx sigură micșorează suprafața de atac și limitează paguba după o intruziune.

Surse

Contact imediat

Fiecare oră contează. Scrieți-ne acum.

Descrieți pe scurt sistemul, versiunea PHP și ce ați observat. Ne vom face auziți, clarificăm situația și lucrăm la distanță până când incidentul este încheiat și documentat.

Ajutor imediat