In breve: una cartella .git pubblica nasce quando un sito viene distribuito con git clone o git pull direttamente nel webroot e il server web non blocca le cartelle nascoste. Si può allora richiamare l'intero codice sorgente con la cronologia delle versioni, comprese le credenziali committate in passato. Verifichi i suoi domini con una semplice chiamata, blocchi subito l'accesso, passi il deployment a pacchetti senza .git e sostituisca le credenziali presenti nella cronologia.
Il codice sorgente da portare via
Git è lo strumento standard per il controllo di versione e per i piccoli team è ovvio usarlo anche per la distribuzione: collegarsi al server, git pull, fatto. Funziona in modo affidabile ed è rapido. Ha però un effetto collaterale che spesso nessuno nota.
Nella cartella del progetto c'è una cartella nascosta .git. Contiene non solo lo stato attuale, ma ogni file in ogni versione mai committata, oltre a messaggi di commit, nomi e indirizzi e-mail degli sviluppatori e riferimenti a server. Se questa cartella si trova nel webroot e il server web la fornisce, chiunque può richiamarla.
Per gli aggressori è un regalo. Con il codice sorgente si possono cercare le vulnerabilità in modo mirato, anziché indovinarle dall'esterno. E nella cronologia si trovano spesso cose che sembravano cancellate da tempo: una password del database dei primi tempi, una chiave API, un file di test con dati dei clienti.
La sua cartella .git è pubblica? Come verificarlo
La verifica richiede pochi secondi e non modifica nulla. Per ogni dominio e sottodominio richiami un file che esiste in ogni repository Git:
# 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/.git/config
# Sul server: esistono cartelle .git sotto i webroot?
find /var/www /srv/www -maxdepth 4 -type d -name ".git" 2>/dev/null
Uno stato 200 significa: la cartella è raggiungibile. Faccia attenzione anche alle sottodirectory. A volte il repository non si trova nel webroot stesso, ma in una cartella di plugin o tema curata separatamente con Git.
Verifichi inoltre gli ambienti di staging e di test. Vengono aggiornati con Git più spesso della produzione e sono spesso raggiungibili con sottodomini indovinabili.
Subito: bloccare l'accesso
Finché il deployment non è modificato, una regola nel server web blocca l'accesso alle cartelle del controllo di versione. Un blocco generale per i file nascosti, come descritto in Proteggere correttamente credenziali e file .env, lo copre. Chi vuole bloccare mirando solo al controllo di versione usa una regola più stretta:
location ~ /\.(git|svn|hg)(/|$) {
return 404;
}
RedirectMatch 404 /\.(git|svn|hg)(/|$)
Poi ripeta la verifica sopra, con una vera chiamata dall'esterno: un test di configurazione riuscito dice solo che la sintassi è corretta, non che la regola abbia effetto prima di altre regole per i file statici. Con pannelli come Plesk o cPanel inserisca la regola nelle direttive aggiuntive previste, affinché non vada persa alla prossima generazione della configurazione.
Se la cartella era raggiungibile, tratti come note tutte le credenziali che sono mai state nel repository. Il solo blocco allora non basta, i valori vanno sostituiti.
In modo duraturo: distribuire senza .git nel webroot
Il blocco è una protezione, non una soluzione. In modo duraturo il controllo di versione non appartiene al server di produzione. Strade collaudate, a seconda del suo ambiente:
| Procedimento | Come funziona | Adatto per |
|---|---|---|
| Pacchetto di build dalla CI | La pipeline costruisce un archivio senza .git, il server lo estrae in una nuova directory di release |
Team con CI/CD |
git archive |
Genera un archivio di uno stato senza dati di versione | Piccoli progetti senza pipeline |
rsync con esclusioni |
Trasferisce solo i file necessari | Server classici |
| Immagine container | Il codice viene copiato nell'immagine durante la build, .git escluso con .dockerignore |
Esercizio con container |
Una directory di release per versione con un collegamento simbolico allo stato attuale ha un altro vantaggio: in caso di problemi si può tornare indietro subito. Per le configurazioni con container, CI/CD: ricostruire automaticamente le immagini PHP descrive come rendere riproducibili le build. Lì si dovrebbe anche verificare che .git non finisca nell'immagine.
# Esempio: generare un pacchetto di uno stato senza dati di versione
git archive --format=tar.gz -o release.tar.gz HEAD
Altri file di progetto che non appartengono al webroot
La cartella .git è l'esempio più noto, ma non l'unico. Chi distribuisce intere directory di progetto porta nel webroot altri file che lì non hanno nulla da fare:
- Cartelle di ambienti di sviluppo come
.ideao.vscode, in cui le estensioni per l'upload dei file salvano talvolta indirizzi dei server e credenziali. composer.jsonecomposer.lock, che rivelano le versioni esatte di tutte le librerie e facilitano così la ricerca di vulnerabilità note.- Configurazioni per test, strumenti di build e pipeline, che rivelano hostname e procedure interne.
- Residui di sistemi operativi come
.DS_Store, che contengono gli elenchi dei file di intere directory.
La soluzione è la stessa della cartella .git: fornire solo ciò che deve essere pubblico, idealmente tramite una sottocartella propria come webroot. Chi comunque passa il deployment a pacchetti stabilisce subito un elenco di file esclusi e lo verifica a ogni nuovo strumento nel progetto.
Se la cartella era aperta: verificare cronologia e log
Se risulta che la cartella .git era raggiungibile, proceda in quest'ordine:
- Bloccare l'accesso e ripetere la verifica.
- Cercare nella cronologia quali segreti siano mai stati committati: file di configurazione,
.env, chiavi, dump del database. - Sostituire le credenziali, tutte quelle trovate nel passo 2, anche se oggi non compaiono più nel codice.
- Analizzare i log di accesso, per vedere se file sotto
/.git/siano stati richiamati con stato 200 e da quali indirizzi. Come si fa lo mostra Analizzare i log del server web dopo un attacco. - Verificare il codice sorgente in modo mirato, perché gli aggressori ora lo conoscono. Le debolezze note andrebbero risolte con priorità.
- Chiarire la protezione dei dati, se nella cronologia c'erano dati personali, ad esempio esportazioni di test. La valutazione spetta al suo responsabile della protezione dei dati.
Gli strumenti per cercare segreti nei repository appartengono poi stabilmente alla pipeline. OWASP raccomanda espressamente tali verifiche, come hook prima del commit e nella CI.
Come aiuta concretamente PHP SOS?
- Verifichiamo tutti i suoi domini e sottodomini alla ricerca di cartelle del controllo di versione raggiungibili.
- Blocchiamo subito l'accesso e passiamo il deployment a pacchetti senza dati di versione.
- Cerchiamo segreti nella cronologia e accompagniamo la sostituzione degli accessi interessati.
- Analizziamo i log di accesso e documentiamo se e quando i dati sono stati richiamati.
Queste misure fanno parte del nostro hardening del server per server web PHP.
Domande frequenti
Come nasce una cartella .git pubblica?
Di solito da un deployment con git clone o git pull direttamente nel webroot. La cartella .git con l'intera cronologia delle versioni si trova allora accanto a index.php e, senza un blocco, il server web ne fornisce i file.
Basta cancellare la cartella .git?
Per il futuro sì, per il passato no. Se la cartella era raggiungibile, il contenuto può essere già stato copiato. Le credenziali che in qualsiasi momento si trovavano nel repository andrebbero quindi sostituite.
Serve rimuovere a posteriori le credenziali dalla cronologia di Git?
Evita che le nuove copie le contengano. Chi ha già scaricato il repository possiede ancora le vecchie versioni. Decisiva è quindi la sostituzione delle credenziali, non solo la riscrittura della cronologia.
Riguarda anche altri sistemi di controllo di versione?
Sì. Anche cartelle come .svn o .hg contengono dati di progetto e non dovrebbero mai essere raggiungibili nel webroot. Un blocco generale per file e cartelle con il punto iniziale copre tutti questi casi.