L'hardening di GLPI raramente fallisce per uno zero-day. Fallisce per l'installer dimenticato, per la web root puntata alla directory sbagliata e per il cookie di sessione senza il flag Secure dietro il proxy. Questa guida è la checklist che applichiamo nella manutenzione di ambienti dei clienti: i comandi, il virtual host e le query di diagnostica che usiamo per chiudere la superficie d'attacco di un GLPI in produzione.
Come viene davvero compromesso un GLPI
Su decine di ambienti in manutenzione lo schema si ripete: la compromissione non arriva quasi mai da una falla esotica del core. Arriva dalla configurazione. I quattro vettori che troviamo più spesso, in ordine, sono: (1) install/install.php mai rimosso dopo il deploy; (2) il DocumentRoot puntato alla radice dell'installazione invece che a public/, che lascia files/_log/ e i backup di configurazione servibili come testo; (3) credenziali di default (glpi/glpi) ancora attive; e (4) il TLS che termina sul proxy inverso con il backend in HTTP semplice e il cookie di sessione senza Secure. Nessuno richiede un exploit, solo un curl. Inizia l'audit provando esattamente questo:
# Installer ancora online? (atteso: 404)
curl -s -o /dev/null -w "%{http_code}\n" https://glpi.cliente.com/install/install.php
# Log degli errori esposto? (atteso: 403/404, MAI 200 con contenuto)
curl -s https://glpi.cliente.com/files/_log/php-errors.log | head
# Backup di config che espone le credenziali del database? (atteso: niente)
curl -s https://glpi.cliente.com/config/config_db.php.bak | head
Se uno di questi restituisce contenuto, ferma tutto: l'ambiente è esposto adesso, e correggerlo è priorità zero.
1. Chiudi la superficie: web root in public/ e nessun residuo di installazione
- Punta il
DocumentRoot(orootsu Nginx) a/var/www/glpi/public, mai a/var/www/glpi. Da GLPI 10 solo la cartellapublic/deve essere la web root. - Rimuovi
install/install.phpdopo aver completato l'installazione o l'aggiornamento. L'aggiornamento ricrea quel file: l'errore comune è aggiornare GLPI e dimenticare di rimuoverlo di nuovo. - Assicurati che
config/,files/e qualsiasi.bako.gitrestino fuori dalla portata del server web.
2. Virtual host: radice corretta, header e solo index.php che esegue PHP
Lo standard di GLPI 10 è instradare tutto tramite public/index.php e non lasciare che nessun altro .php venga eseguito direttamente. Questo è il server block che usiamo come base su Nginx:
# /etc/nginx/sites-available/glpi.conf
server {
listen 443 ssl;
http2 on;
server_name glpi.cliente.com;
root /var/www/glpi/public; # mai /var/www/glpi
index index.php;
ssl_certificate /etc/letsencrypt/live/glpi.cliente.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/glpi.cliente.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Header di sicurezza
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
try_files $uri /index.php$is_args$args;
}
# Solo index.php instrada PHP
location ~ ^/index\.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
# Qualsiasi altro .php: nega
location ~ \.php$ {
return 404;
}
}
Su Apache l'equivalente è DocumentRoot /var/www/glpi/public con il blocco <Directory> ristretto e gli stessi header via Header set. Una nota sul campo: abilita Strict-Transport-Security (HSTS) solo dopo che il certificato è pienamente funzionante. Con HSTS attivo e un TLS rotto blocchi l'intero dominio nel browser degli utenti per tutta la durata del max-age.
3. Sessione e cookie: la fuga silenziosa dietro il proxy
Questo è il rilievo che più spesso passa inosservato. Quando il TLS termina sul proxy (Nginx/HAProxy) e GLPI gira in HTTP sul backend, il cookie di sessione deve restare marcato come Secure e HttpOnly. In Configurazione > Generale, nella scheda sicurezza, forza i cookie sicuri e una policy di password (lunghezza minima, complessità, scadenza). Senza di ciò, il cookie di sessione viaggia sul salto interno HTTP senza Secure, e basta catturare il traffico su quel segmento per dirottare la sessione di un tecnico connesso. Regola anche la durata della sessione su un valore coerente con il rischio dell'ambiente, invece del lungo default.
4. Account e autenticazione
Cambia subito le password di glpi, tech, normal e post-only, oppure disattiva quelli che non usi. Esegui questa diagnostica direttamente sul database per mappare ciò che dipende ancora da una password locale (authtype = 1) ed è candidato a MFA/SSO o disattivazione:
-- Account GLPI di default ancora attivi
SELECT name, is_active, last_login
FROM glpi_users
WHERE name IN ('glpi','tech','normal','post-only');
-- Tutti gli account con password LOCALE attiva (authtype = 1)
-- authtype: 1=locale 2=mail 3=LDAP 4=esterna 5=CAS
SELECT id, name, is_active, last_login
FROM glpi_users
WHERE authtype = 1 AND is_active = 1
ORDER BY last_login;
La raccomandazione per la produzione: SSO (Azure AD/Entra ID o altro provider) con MFA, e login locale limitato a un unico account di emergenza (break-glass) con password forte custodita in un vault. Il core di GLPI non ha MFA nativo né blocco per tentativi: per l'MFA usa un plugin adeguato o l'SSO stesso; per il brute force, metti GLPI dietro fail2ban che legge il log di accesso del proxy. Vedi anche la nostra guida al SSO con Azure AD/Entra ID.
5. Permessi: codice in sola lettura, scrittura solo dove serve
Il principio è semplice: l'utente di PHP-FPM (www-data) deve leggere il codice, ma non scriverlo mai. L'unico albero in scrittura è GLPI_VAR_DIR. Così, anche una falla dell'applicazione non può persistere codice malevolo nella directory servita.
| Directory | Ruolo | Proprietario:gruppo | Scrittura www-data |
|---|---|---|---|
| /var/www/glpi | Codice + web root public/ | root:www-data | No (750 / 640) |
| /etc/glpi | Config (config_db.php) | root:www-data | No (750 / 640) |
| /var/lib/glpi | GLPI_VAR_DIR (files, cache, sessioni) | www-data:www-data | Sì (750) |
| /var/log/glpi | Log dell'applicazione | www-data:www-data | Sì (750) |
Spostare config/ e files/ fuori dalla web root (via GLPI_CONFIG_DIR e GLPI_VAR_DIR) è il layout che adottiamo di default: se un giorno la web root viene esposta per errore, config e dati non vanno con essa.
6. Aggiornamenti e monitoraggio continuo
Tieni la versione aggiornata. La maggior parte dei CVE di GLPI ha già una patch quando finisce sulle notizie; il rischio reale è l'ambiente fermo tre versioni indietro. Monitora i tentativi di autenticazione (picchi di login falliti suggeriscono brute force) in Zabbix/Grafana e segui i CVE della tua versione installata. Per questo usiamo il modulo CVE Scan, che incrocia la versione di GLPI con i CVE noti e verifica punti dell'ambiente. E non trattare l'hardening senza un piano di ripristino: vedi la guida a backup e disaster recovery.
Errori comuni che vediamo in manutenzione
- Backup di config nella web root: qualcuno salva
config_db.php.bakprima di modificare; poiché.baknon viene eseguito da PHP, il server consegna le credenziali del database in testo semplice. - Alias legacy che sopravvive: il nuovo vhost punta a
public/, ma un vecchioAlias /glpicontinua a esporre la radice. - HSTS prima del certificato: attivare HSTS con un TLS incompleto blocca il dominio nel browser degli utenti.
- Login locale disattivato senza break-glass: tagliano il login locale affidandosi al 100% all'SSO e, quando l'SSO cade, nessuno entra come admin.
Farlo una volta è facile; mantenerlo su decine di ambienti dei clienti, con aggiornamenti ricorrenti che ricreano install/, è lavoro di manutenzione. È esattamente ciò che fa NexTool: la manutenzione GLPI di NexTool valida la web root, irrobustisce il virtual host, rivede i permessi ed esegue questa batteria di verifica come parte del ciclo di manutenzione.
Este conteúdo foi produzido com auxílio de inteligência artificial e revisado pela equipe Nextool Solutions.