Indice dei contenuti dell'articolo:
Nel mondo dell’hosting web esiste una di quelle “verità” ripetute talmente tante volte da essere diventata quasi dogma: le directory devono avere permessi 755 e i file devono avere permessi 644. Lo dicono guide, tutorial, pannelli di controllo, provider generalisti, documentazioni di supporto, forum e perfino alcuni strumenti automatici di ripristino permessi. Il problema è che questa regola, pur essendo comoda e spesso funzionante, non è necessariamente corretta dal punto di vista della sicurezza.
Il punto non è sostenere che un sito con directory a 755 e file a 644 sia automaticamente compromesso o insicuro in senso assoluto. Sarebbe una semplificazione banale, e sotto un certo punto di vista anche una falsità. Il punto è un altro: 755 e 644 sono permessi pensati per garantire compatibilità universale, non per rispettare davvero il principio del minimo privilegio. Ed è qui che nasce l’equivoco, o meglio, il peccato originale di buona parte dell’hosting commerciale basato su pannelli di controllo come cPanel, Plesk e simili.
In un sistema Linux multiutente, la terza cifra dei permessi, quella riferita agli “others”, cioè a tutti gli altri utenti del sistema, non dovrebbe essere usata come scorciatoia per far funzionare il web server. Se il web server deve leggere i file di un sito, allora dovrebbe poterlo fare perché appartiene al gruppo corretto, perché il processo PHP gira con l’utente corretto, oppure perché l’architettura del servizio è stata progettata con criterio. Non perché abbiamo deciso di rendere leggibile il sito a qualunque utente locale del sistema.
Il significato reale di 755 e 644
Partiamo dalla base. Un permesso 755 su una directory significa:
rwxr-xr-x
Il proprietario può leggere, scrivere ed entrare nella directory. Il gruppo può leggere ed entrare. Tutti gli altri possono leggere ed entrare. Su una directory, il bit di esecuzione non significa “eseguire un programma”, ma attraversare la directory, cioè poterci entrare, raggiungere file e sottodirectory e risolvere il percorso.
Un permesso 644 su un file significa:
rw-r--r--
Il proprietario può leggere e scrivere. Il gruppo può leggere. Tutti gli altri possono leggere. Quindi, se un file PHP, un file di configurazione o un file testuale ha permessi 644, qualsiasi utente locale non proprietario e non appartenente al gruppo può comunque leggerlo, a condizione che abbia accesso al percorso superiore.
Qui molti cadono nell’errore concettuale: “tanto via web non si può leggere il file PHP sorgente”. Vero, se il web server è configurato correttamente. Ma i permessi Linux non regolano soltanto l’accesso HTTP. Regolano anche l’accesso locale da shell, da processi di sistema, da script compromessi, da utenti confinati male, da job cron, da tool di backup, da account FTP o SFTP, da altri siti ospitati sulla stessa macchina e da qualunque processo che riesca a girare con un utente locale diverso.
Dire che 755 e 644 “vanno bene” significa spesso ignorare il contesto multiutente in cui quei permessi vengono applicati.
Perché i pannelli continuano a usare 755 e 644?
La risposta è scomoda ma semplice: perché funzionano quasi sempre. I pannelli di controllo sono prodotti generalisti. Devono supportare stack vecchi e nuovi, server configurati bene e server configurati male, Apache con mod_php, Apache con PHP-FPM, Nginx come reverse proxy, LiteSpeed, LSAPI, suPHP, suexec, FastCGI, utenti FTP, File Manager web, backup, restore, migrazioni, plugin WordPress, installer automatici, vecchi CMS, script scritti male e clienti che caricano file con permessi improbabili.
In questo scenario, 755 per le directory e 644 per i file sono la via più semplice per evitare ticket di assistenza. Se il processo web non appartiene al gruppo corretto, se Apache gira come nobody, se Nginx gira come nginx, se il PHP-FPM pool non è perfettamente allineato all’utente del sito, se il File Manager deve comunque visualizzare e manipolare i file, quei permessi garantiscono una cosa: il sito probabilmente continuerà a rispondere.
Ma questo non li rende i permessi migliori. Li rende i permessi più comodi per il vendor del pannello e per il provider che vuole ridurre i problemi di compatibilità. È una differenza enorme.
Quando un pannello imposta automaticamente directory a 755 e file a 644, sta implicitamente dicendo: “non so con certezza quale utente o gruppo dovrà leggere questi file, quindi apro la lettura anche agli altri”. È una scelta pragmatica. Ma dal punto di vista sistemistico è una scorciatoia.
Il principio del minimo privilegio
Il principio del minimo privilegio dice che ogni utente, processo o servizio dovrebbe avere solo i permessi strettamente necessari per svolgere la propria funzione. Applicato ai file di un sito web, questo significa che:
- l’utente proprietario del sito deve poter leggere e scrivere i file;
- il processo PHP deve poter leggere i file PHP ed eventualmente scrivere solo nelle directory previste;
- il web server deve poter leggere gli asset statici che deve servire direttamente;
- gli altri utenti del sistema non dovrebbero poter leggere nulla;
- i file sensibili non dovrebbero essere leggibili da processi non necessari.
Se prendiamo sul serio questo principio, la coppia 755/644 appare subito troppo larga. La configurazione più coerente diventa invece:
Directory: 750 File: 640
O, in alcuni casi ancora più restrittivi:
Directory: 750 o 700 File: 640 o 600
Per file particolarmente sensibili come wp-config.php, .env, configuration.php di Joomla o app/etc/env.php di Magento, può avere senso scendere ulteriormente, compatibilmente con il modo in cui PHP accede al file.
WordPress, PHP-FPM e Nginx: perché il modello cambia
Una parte importante della confusione nasce dal fatto che molte raccomandazioni storiche derivano da ambienti Apache tradizionali, spesso con mod_php o configurazioni dove il web server aveva bisogno di leggere direttamente buona parte del contenuto. Ma nel mondo moderno, soprattutto in ambienti professionali, un sito WordPress o PHP viene spesso eseguito con un modello diverso:
- Nginx gestisce la connessione HTTP e serve gli asset statici;
- PHP-FPM esegue il codice PHP;
- ogni pool PHP-FPM può girare come utente specifico del sito;
- il codice PHP non viene “letto da Nginx” per essere interpretato, ma passato a PHP-FPM tramite FastCGI;
- il processo PHP può essere isolato per utente, dominio o subscription.
In questo scenario, continuare a ragionare come se tutto dovesse essere leggibile da “others” è tecnicamente arretrato. Se PHP-FPM gira come l’utente del sito, i file PHP possono essere letti dall’utente proprietario. Se Nginx deve servire file statici, può accedere a quei file tramite gruppo. Non c’è alcun bisogno logico di lasciare il permesso di lettura al resto del mondo locale.
Il modello corretto è progettare ownership e gruppi in modo coerente. Ad esempio:
owner: utente_sito group: web-utente_sito directory: 750 file: 640
In questo schema, l’utente del sito mantiene il controllo dei file, mentre il gruppo consente l’accesso ai processi autorizzati, ad esempio Nginx o un servizio specifico. Tutti gli altri non hanno accesso.
Il problema del gruppo nginx usato globalmente
Una soluzione apparentemente semplice potrebbe essere: “mettiamo Nginx nel gruppo dell’utente” oppure “assegniamo i file al gruppo nginx”. Il ragionamento è corretto nella direzione, ma va applicato con attenzione.
Un esempio grezzo potrebbe essere:
chown -R nomesito:nginx /home/nomesito/public_html
find /home/nomesito/public_html -type d -exec chmod 750 {} ;
find /home/nomesito/public_html -type f -exec chmod 640 {} ;
Questo funziona: Nginx, essendo nel gruppo, può attraversare le directory e leggere i file. Gli utenti “others” non possono fare nulla. Tuttavia, se tutti i siti del server usano il gruppo globale nginx, allora qualsiasi processo che gira come Nginx può potenzialmente leggere i file di tutti quei siti. In un server mono-sito può essere accettabile; in un ambiente multiutente non è il massimo dell’isolamento.
La soluzione più elegante è usare gruppi dedicati per sito o per contesto applicativo:
groupadd web-nomesito
usermod -aG web-nomesito nginx
usermod -aG web-nomesito nomesito
chown -R nomesito:web-nomesito /home/nomesito/public_html
find /home/nomesito/public_html -type d -exec chmod 750 {} ;
find /home/nomesito/public_html -type f -exec chmod 640 {} ;
Per mantenere coerente il gruppo sui nuovi file creati dentro le directory, si può usare anche il bit setgid sulle directory:
find /home/nomesito/public_html -type d -exec chmod g+s {} ;
In questo modo, i nuovi file creati dentro quelle directory ereditano il gruppo della directory padre. Non è una bacchetta magica, perché bisogna comunque gestire umask, deploy, SFTP, processi PHP e strumenti di aggiornamento, ma è un modello molto più sensato rispetto ad aprire tutto a “others”.
Perché 750/640 è più corretto
Con directory a 750 e file a 640 si ottiene una separazione molto più pulita:
rwxr-x--- directory rw-r----- file
Il proprietario ha pieno controllo. Il gruppo può leggere e attraversare. Gli altri non possono fare nulla. Questo significa che un altro utente locale non può curiosare nei file del sito solo perché il pannello ha deciso di usare permessi permissivi per evitare problemi.
In ambito WordPress, la differenza non è accademica. Dentro un’installazione WordPress possiamo trovare file di configurazione, credenziali database, chiavi di autenticazione, plugin custom, backup dimenticati, export, log, dump SQL, file temporanei, cache, configurazioni di servizi esterni, token API, credenziali SMTP e molto altro. Certo, molti di questi file non dovrebbero stare nel document root. Ma sappiamo bene come funziona il mondo reale: i siti accumulano materiale, plugin, cartelle temporanee e residui di migrazioni.
Se tutto è leggibile da “others”, qualunque debolezza nell’isolamento locale può trasformarsi in una perdita di confidenzialità. Non serve necessariamente una vulnerabilità remota spettacolare. A volte basta un account compromesso sullo stesso server, uno script male isolato, un cron eseguito con privilegi inadeguati o una configurazione multiutente superficiale.
Una configurazione più corretta per WordPress
Su uno stack moderno con Nginx e PHP-FPM per utente, un’impostazione più sensata potrebbe essere questa:
SITE_USER="nomesito"
SITE_GROUP="web-nomesito"
SITE_PATH="/home/nomesito/public_html"
groupadd -f "$SITE_GROUP"
usermod -aG "$SITE_GROUP" nginx
usermod -aG "$SITE_GROUP" "$SITE_USER"
chown -R "$SITE_USER:$SITE_GROUP" "$SITE_PATH"
find "$SITE_PATH" -type d -exec chmod 750 {} ;
find "$SITE_PATH" -type f -exec chmod 640 {} ;
find "$SITE_PATH" -type d -exec chmod g+s {} ;
chmod 600 "$SITE_PATH/wp-config.php"
Naturalmente questo è un esempio concettuale, non una ricetta da lanciare alla cieca su qualsiasi server. Prima bisogna verificare come gira PHP-FPM, con quale utente, quale gruppo primario usa, come vengono creati i file dagli aggiornamenti WordPress, come opera il sistema di deploy, se sono presenti ACL, se c’è SELinux, AppArmor, CageFS, un pannello di controllo o altri meccanismi di isolamento.
In alcuni casi può essere più adatto 750/640. In altri 750/650, se si vuole mantenere il bit di esecuzione su alcuni file specifici o se ci sono particolari esigenze operative. In altri ancora 700/600 per sezioni non servite direttamente dal web. Il punto non è idolatrare un numero, ma smettere di considerare 755/644 come una legge universale.
La responsabilità dei pannelli di controllo
Plesk e cPanel non sono “sbagliati” perché non sanno cosa siano i permessi Linux. Sono prodotti maturi, complessi, usati in contesti enormemente diversi. Il loro problema è un altro: devono scegliere default che funzionino nel maggior numero possibile di scenari. E quando un software deve scegliere tra sicurezza rigorosa e riduzione dei problemi di supporto, spesso sceglie la seconda.
Il risultato è che un’impostazione nata per compatibilità diventa, nella percezione comune, una raccomandazione di sicurezza. E questo è pericoloso. Perché il sistemista inesperto legge “755 directory, 644 file” e pensa: “questa è la configurazione corretta”. In realtà dovrebbe leggere: “questa è la configurazione che probabilmente evita errori 403 nella maggior parte degli ambienti generici”.
La differenza è sostanziale. Un valore di default non è automaticamente una best practice. Un valore che evita ticket non è automaticamente il valore più sicuro. Una configurazione tollerata da un pannello non è necessariamente la configurazione ideale per un ambiente managed, moderno e progettato con competenza.
Il caso dei file scrivibili
Un altro tema spesso confuso è la scrivibilità. WordPress, plugin, cache, upload e aggiornamenti hanno bisogno di scrivere in alcune directory. Ma da questo non deriva che tutto il sito debba essere scrivibile o leggibile da tutti.
Una gestione più rigorosa dovrebbe distinguere tra:
- codice applicativo, che dovrebbe essere modificabile solo dal proprietario o dal sistema di deploy;
- directory di upload, che devono essere scrivibili dal processo PHP;
- directory di cache, che devono essere scrivibili dal processo applicativo;
- file di configurazione, che dovrebbero essere il più possibile restrittivi;
- asset statici, che Nginx deve poter leggere ma non modificare.
Una policy matura non dice “tutto 755 e 644”. Dice: “chi deve leggere? chi deve scrivere? chi deve attraversare? chi non deve avere alcun accesso?”. Solo dopo si scelgono chmod, chown, gruppi, ACL e umask.
Conclusione: il problema non è Linux, è la pigrizia del default
Linux offre già tutti gli strumenti per fare le cose bene: utenti, gruppi, permessi, ACL, umask, setgid, isolamento dei processi, PHP-FPM pool separati, chroot, container, namespace, sistemi MAC come SELinux e AppArmor. Il problema non è il modello Unix. Il problema è l’abitudine a usare configurazioni lasche perché “così funziona”.
I pannelli di controllo hanno storicamente promosso o normalizzato permessi come 755 e 644 perché sono semplici, compatibili e riducono il rischio di rompere siti mal configurati. Ma in un ambiente professionale, soprattutto per WordPress e più in generale per siti PHP serviti da Nginx con backend PHP-FPM, esistono configurazioni più corrette, più coerenti e più rispettose del principio del minimo privilegio.
Directory a 750 e file a 640, con ownership e gruppi progettati correttamente, rappresentano un modello più sano. Non sempre immediato da applicare, non sempre compatibile con qualsiasi pannello senza adattamenti, ma concettualmente superiore. Il web server non deve leggere perché “tutti possono leggere”. Deve leggere perché è stato autorizzato a farlo. PHP non deve scrivere ovunque. Deve scrivere solo dove serve. Gli altri utenti del sistema non devono poter curiosare nel codice e nelle configurazioni di un sito che non appartiene loro.
La vera sicurezza sistemistica non consiste nel copiare comandi da una guida generica, ma nel capire il modello di esecuzione del proprio stack. Se il server è progettato bene, 755 e 644 non sono una necessità: sono solo un compromesso ereditato dal passato. E come molti compromessi storici dell’hosting condiviso, continuano a sopravvivere non perché siano giusti, ma perché sono comodi.