Situazione attuale: PHP2Shell. Due vulnerabilità critiche di PHP (CVSS 9,2) consentono codice dannoso senza autenticazione. Patch dal 21/10/2026.Che cosa fare ora →

Configurare Nginx per PHP in sicurezza

La maggior parte dei punti deboli nelle configurazioni Nginx per PHP non è in Nginx, ma in poche righe della location PHP. Come configurare il passaggio a PHP-FPM in modo che vengano eseguiti solo gli script voluti.

Stato 6 min di letturaHardening e configurazione

In breve: per configurare Nginx per PHP in sicurezza, passi a PHP-FPM solo script che esistono davvero, nelle applicazioni con front controller addirittura solo index.php. A ciò si aggiungono dotfile bloccati come .git e .env, un server predefinito per hostname sconosciuti, limiti di dimensione adatti e security.limit_extensions = .php nel pool. Non protegge dalle vulnerabilità in PHP stesso, ma limita ciò che è eseguibile dopo un errore.

Le righe più pericolose stanno nella location PHP

Da PHP2Shell molti team verificano le proprie versioni e i pool di PHP-FPM, come descrive la pagina Mettere in sicurezza Nginx con PHP-FPM, e dopo l'aggiornamento riavviano tutti i worker. Un secondo sguardo va alla configurazione di Nginx stessa. Lì si decide quali file vengano eseguiti come PHP.

In molte configurazioni c'è un blocco che inoltra a PHP-FPM ogni richiesta a .php, ovunque si trovi il file. Se un file PHP iniettato finisce in una cartella di upload, il server lo esegue. Da un errore di file nasce così una backdoor.

Questo articolo si concentra sul lato Nginx: quali direttive contano, come agisce l'ordine dei blocchi location e come testare il risultato.

Come Nginx decide quale blocco si applica

Chi vuole configurare Nginx per PHP in sicurezza deve conoscere la scelta dei blocchi location. Secondo la documentazione di Nginx, si svolge così:

  1. Una corrispondenza esatta con location = termina subito la ricerca.
  2. Tra le location con prefisso viene memorizzata la più lunga corrispondente. Se porta ^~, non vengono più controllate espressioni regolari.
  3. Altrimenti le espressioni regolari (~, ~*) vengono controllate nell'ordine del file di configurazione; vince la prima corrispondenza.
  4. Se nessuna espressione regolare corrisponde, vale la location con prefisso memorizzata.

Ne derivano due regole pratiche. Un blocco per PHP nelle cartelle di upload deve essere creato come prefisso ^~ oppure stare, come espressione regolare, prima del blocco PHP generale. E una normale location con prefisso come location /uploads/ non protegge, perché l'espressione regolare per .php la scavalca.

Una configurazione di base sicura

L'esempio seguente mostra un blocco server per un'applicazione con front controller, come è usuale in Laravel, Symfony, Shopware 6 o in molti sviluppi propri. Percorsi, socket e certificati li adatti.

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;

    # Consentire Let's Encrypt e altri percorsi noti
    location ^~ /.well-known/ {
        try_files $uri =404;
    }

    # Bloccare file e cartelle nascosti (.git, .env, .htaccess)
    location ~ /\. {
        deny all;
    }

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

    # Solo il front controller viene passato a 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;
    }

    # Ogni altro file PHP non viene eseguito
    location ~ \.php$ {
        return 404;
    }
}

$realpath_root risolve i link simbolici. È importante nei deployment con un symlink variabile verso la release corrente, affinché PHP-FPM e OPcache vedano il percorso giusto. Tenga presente inoltre: secondo la documentazione di Nginx, le direttive fastcgi_param vengono ereditate dai livelli superiori solo se al livello corrente non ce ne sono di proprie. Per questo include fastcgi_params; va nello stesso blocco.

I CMS classici come WordPress, TYPO3 o Contao hanno più punti di ingresso. Lì sostituisca il blocco del front controller con una location PHP generale che passa solo file esistenti (try_files $uri =404;) e blocchi l'esecuzione in tutte le cartelle scrivibili. Come ottenerlo lo spiega Vietare l'esecuzione di PHP nelle cartelle di upload.

La seconda protezione in PHP-FPM

Nginx decide che cosa viene inoltrato, PHP-FPM decide che cosa esegue. Secondo il manuale PHP, PHP-FPM per impostazione predefinita esegue file con .php e .phar e raccomanda esso stesso di limitarsi a .php. Ciò intercetta errori di configurazione nel server web.

; nel pool, ad es. /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

Il socket dovrebbe essere raggiungibile solo da Nginx. Le porte FPM nella rete, ad esempio 9000, non vanno aperte verso l'esterno. Come il server mostri in generale solo le porte necessarie lo descrive Firewall per server web: aprire solo le porte necessarie.

Hostname sconosciuti e altre regolazioni

Senza un server predefinito proprio, Nginx risponde alle richieste a hostname sconosciuti con il primo blocco server corrispondente. Le scansioni automatiche che si rivolgono solo all'indirizzo IP finiscono allora direttamente nella Sua applicazione. Un server predefinito proprio chiude tali richieste senza risposta.

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

Altri punti che si sono dimostrati validi:

Regolazione Raccomandazione Scopo
server_tokens off nessun numero di versione in header e pagine di errore
client_max_body_size adatto a post_max_size rifiutare presto le richieste grandi
autoindex disattivato (predefinito) nessun elenco di directory
fastcgi_hide_header X-Powered-By nessuna versione di PHP verso l'esterno
Pagine di stato pm.status_path solo interno nessun dato operativo pubblico
File di backup bloccare o rimuovere .sql, .zip, .bak nel webroot nessun download di database

Maggiori informazioni sulle indicazioni di versione sono nell'articolo expose_php e header Server.

Un'altra regolazione riguarda i metodi HTTP consentiti. La maggior parte dei siti ha bisogno solo di GET, HEAD e POST. Con limit_except si possono rifiutare altri metodi in una location; secondo la documentazione di Nginx, l'abilitazione di GET consente automaticamente anche HEAD. Verifichi prima se le interfacce della Sua applicazione usano ad esempio PUT o DELETE, perché le API REST lo fanno spesso.

Testare prima di ricaricare

Ogni modifica la verifichi prima con nginx -t e ricarichi Nginx solo dopo. Poi testi il comportamento dall'esterno con normali richieste al Suo dominio:

sudo nginx -t && sudo systemctl reload nginx
# Atteso: 403 o 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
# Atteso: 404, perché viene eseguito solo il front controller
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# Quali blocchi passano a PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"

Prima di ogni modifica più grande metta al sicuro con la data l'intero output di nginx -T. Contiene l'intera configurazione effettiva, compresi tutti i file inclusi. Se dopo una modifica qualcosa va storto, il confronto mostra subito che cosa differisce. Alla prossima vulnerabilità critica avrà inoltre una base affidabile per l'inventario, senza dover prima raccogliere i file.

Consiglio

Modifichi la configurazione prima su un ambiente di test o su una copia del blocco server. Un punto di ingresso dimenticato, ad esempio un callback di pagamento, altrimenti si nota solo quando mancano gli ordini.

Come aiuta PHP SOS in concreto?

  • Leggere la configurazione: analizziamo l'intera configurazione di Nginx con nginx -T e assegniamo ogni passaggio a PHP al relativo sito e pool.
  • Definire i punti di ingresso: insieme ai Suoi sviluppatori stabiliamo quali script devono essere eseguiti e blocchiamo il resto.
  • Attuare e testare: adattiamo blocchi server e pool, verifichiamo con nginx -t e testiamo moduli, percorsi di pagamento e upload.
  • Proteggere nel tempo: la configurazione diventa parte del nostro hardening del server e della documentazione del Suo server.

Domande frequenti

Nginx deve essere riavviato dopo un aggiornamento di PHP?

Non per la patch di PHP, perché Nginx non contiene PHP. Devono essere riavviati tutti i servizi PHP-FPM. Se modifica anche la configurazione di Nginx, la verifichi prima con nginx -t e poi ricarichi Nginx.

Perché passare a PHP solo index.php?

Molte applicazioni moderne hanno un unico punto di ingresso, il front controller. Se solo questo file viene passato a PHP-FPM, un file PHP iniettato altrove non può essere eseguito tramite il browser. Nei sistemi con molti punti di ingresso questo schema non è possibile.

Che cosa serve security.limit_extensions in PHP-FPM?

L'impostazione stabilisce quali estensioni di file PHP-FPM esegue come script. Secondo il manuale PHP il valore predefinito è .php .phar; si raccomanda di limitarsi a .php. Intercetta errori nella configurazione del server web, ma non la sostituisce.

Le regole di Nginx proteggono da PHP2Shell?

No. PHP2Shell si trova nell'interprete PHP e si chiude solo con l'aggiornamento a una versione corretta e il riavvio di tutti i worker. Una configurazione sicura di Nginx riduce la superficie d'attacco e limita il danno dopo un'intrusione.

Fonti

Contatto immediato

Ogni ora conta. Ci scriva adesso.

Descriva brevemente sistema, versione di PHP e quanto osservato. Ci faremo sentire, chiariremo la situazione e lavoreremo da remoto fino alla chiusura e alla documentazione dell'incidente.

Aiuto immediato