# Trova vulnerabilità nei web server: 30+ hardening check

> Linter online di config Apache (.htaccess, vhost) e Nginx (server, location): 30+ check su SSL/TLS, header CSP, HSTS, Permissions-Policy, WAF. Niente upload.

Strumento gratuito nel browser (nessun upload): https://www.mauriziofonte.it/strumenti/audit-config-apache-nginx

Incolla un blocco di config **Apache** (`.htaccess`, `VirtualHost`, `Directory`, `Location`) o **Nginx** (`server`, `location`, `upstream`) e ottieni un audit security-first context-aware: il tool fa parsing AST nativo (no regex grep) e applica oltre 30 check su SSL/TLS deboli, header di sicurezza con **validatori di valore** per CSP (`unsafe-inline`, wildcard, `report-uri`), HSTS (`max-age`, `includeSubDomains`, `preload`), Permissions-Policy, forward secrecy, AEAD, HTTP/2, OCSP stapling, mod_security WAF, rate limiting su endpoint di autenticazione, redirect HTTP->HTTPS, override semantica di `add_header` Nginx (la regola che azzera gli header del server parent quando una location ne aggiunge uno proprio). Parser e regole girano interamente nel browser: la config non lascia mai la pagina.

## Come usare il linter

1. **Recupera la config** - **Apache**: tipici percorsi `/etc/apache2/sites-enabled/*.conf`, `/etc/httpd/conf.d/*.conf`, oppure il `.htaccess` nella radice del sito. **Nginx**: `/etc/nginx/sites-enabled/*`, `/etc/nginx/conf.d/*.conf`, oppure il file principale `nginx.conf`. Per analisi assistita: salva il blocco in un file `.conf` (o `.htaccess`) e usa il dropzone per caricarlo direttamente.
2. **Incolla nel tool** - Il tool auto-detect il dialect contando le occorrenze di pattern canonici (Apache: tag `<...>` XML-like, ServerTokens, SSLEngine; Nginx: `server { }`, `location`, `add_header`). Se nessun pattern matcha, fallisce con messaggio diagnostico esplicito. L'input non lascia il browser: parser e regole girano in JavaScript locale.
3. **Leggi il report** - Output a tre livelli. **Dialect rilevato** in alto. **Findings ordinati per severity**: critical, high, medium, low, info. **Score aggregato** 0-100. Per ogni rilievo: descrizione del problema, riferimento normativo (Mozilla SSL Configurator, OWASP Secure Headers Project, CVE storiche), remediation pronta da copy-paste nella config.
4. **Esporta o stampa** - **Copia report**: text plain per ticket interni o documenti di hardening. **Esporta per chatbot**: markdown completo con context, findings dettagliati e prompt template, da incollare in ChatGPT/Gemini/Claude per priorizzare la remediation o stimare lo sforzo di fix. **Stampa** del browser per export PDF (CSS print-ottimizzato che nasconde nav e CTA).

## Perché un linter context-aware è il livello giusto di triage

**Le config Apache e Nginx sembrano semplici, sono compositive.** Una direttiva può apparire al top-level, dentro un `<VirtualHost>` Apache, dentro un `server { }` Nginx, dentro una `<Location>` o una `location { }`: il significato cambia con lo scope. Header di sicurezza dichiarati nello scope sbagliato sono presenti formalmente ma non si applicano alla pagina che dovevano proteggere. Cipher modern dichiarati al top-level vengono sovrascritti da una direttiva legacy in un vhost specifico. Il regex grep non vede queste sottigliezze: il parsing AST sì, e questa versione del linter è basata su un parser AST proper scritto in vanilla JS (~750 LOC complessive) che produce un albero navigabile di blocchi e direttive con line number.

**Cosa controlla in concreto.** Il linter applica oltre 30 check su 5 famiglie. **SSL/TLS**: protocolli obsoleti (SSLv2, SSLv3, TLSv1, TLSv1.1) e modern (TLSv1.2, TLSv1.3), cipher weak (RC4, 3DES, EXPORT, NULL) vs cipher strong, presenza di **forward secrecy** (ECDHE/DHE), AEAD (GCM, ChaCha20-Poly1305), OCSP stapling. **Header di sicurezza con value validator**: la differenza con i linter regex-based e\' qui. CSP con `unsafe-inline` in `script-src` = praticamente disabilitata, segnala medium; CSP con wildcard `*`, `unsafe-eval`, mancanza di `report-uri`: tutti finding distinti. HSTS con `max-age` < 6 mesi: medium. HSTS senza `includeSubDomains`: low. HSTS senza `preload`: info. **Information disclosure**: ServerTokens / server_tokens verbose, autoindex on, `/server-status` e `/nginx_status` non restricted. **Availability e hardening**: `listen 80` senza redirect a HTTPS, rate limiting su endpoint di autenticazione (`/login`, `/auth`, `/register`), HTTP/2 abilitato, mod_security WAF presente. **Override semantici Nginx**: il caso classico in cui un `add_header` dentro una location azzera silenziosamente tutti gli `add_header` del server parent per quella location, lasciando la pagina senza HSTS/CSP/X-Frame.

**Differenza fra linter context-aware e linter regex-based.** Il linter precedente di questo tool faceva regex grep su tutto il testo della config: `/Strict-Transport-Security/i.test(text)`. Risultato: HSTS dichiarato dentro `<Location /admin>` contava come HSTS presente, anche se l'header era ovviamente non emesso al di fuori di /admin. Falso negativo grave. Stesso problema con `add_header` Nginx: la presenza nel testo non implica applicazione alla request. Lo stesso vale per protocolli e cipher: una direttiva valida in un vhost non implica che valga per tutti gli altri. Il parser AST risolve in radice questi problemi: ogni finding ha contesto preciso (in quale blocco, a quale linea, con quali argomenti).

**Privacy operativa.** Una config server rivela la struttura completa di un'infrastruttura: hostname, certificati, percorsi del filesystem, backend interni, eventuali proxy cache, eventuali path admin nascosti. Caricarla a un servizio terzo per un audit preliminare e\' un vettore di leak: la config esce dal perimetro, raggiunge un endpoint esterno, viene processata e magari loggata. Qui non parte nessuna richiesta di rete con i dati della config: parser e regole girano interamente nel browser. Verificabile aprendo il pannello Network di DevTools durante il lint.

**Quando il triage statico è il livello giusto.** Casi tipici. (a) Code review di un Pull Request che modifica la config Nginx prima del merge: il linter copre il 70-80% dei pattern di hardening e segnala in modo deterministico. (b) Audit pre-go-live di un nuovo VPS: la config DevOps appena scritta passa il triage prima del deploy in produzione. (c) Self-check periodico: la config che gira da due anni in produzione viene re-lintata per intercettare regressioni introdotte da modifiche puntuali. (d) Pre-engagement audit di un cliente che chiede una review della propria config: trenta secondi di lint danno la lista dei findings da approfondire con esercizio di hardening serio.

**Limite di scope.** Il linter analizza il testo della config: non interroga lo stato runtime del server, non risolve `Include` / `include` verso file esterni, non valuta certificati X.509 in scadenza, non verifica che il backend dietro un `proxy_pass` risponda davvero in HTTPS, non controlla i log per attacchi attivi. Per quegli aspetti servono assessment manuali, scanner online (SSLLabs, Mozilla Observatory) e monitoring CVE in continuo. Il linter è un triage rapido, non un sostituto.

## Glossario

- **VirtualHost (Apache)**: Blocco `<VirtualHost>` che definisce le direttive applicate a una specifica combinazione IP:porta. Una config Apache puo\' avere N VirtualHost, ognuno con SSL, header, certificate file diversi. Il linter analizza ogni vhost separatamente.
- **server { } (Nginx)**: Equivalente Nginx del VirtualHost Apache. Definisce le direttive per una combinazione listen + server_name. Annidato dentro `http { }` nella config principale, oppure top-level nelle conf incluse via `include`.
- **AST (Abstract Syntax Tree)**: Rappresentazione strutturata della config dopo il parsing. Ogni direttiva e blocco diventa un nodo con type, name, args, line, children. Permette di rispondere a domande di scope e di contesto che il regex grep non vede.
- **HSTS (Strict-Transport-Security)**: Header HTTP che istruisce il browser a usare solo HTTPS per il dominio per `max-age` secondi. Mitigation contro downgrade attack su TLS. Best practice: `max-age=31536000; includeSubDomains; preload` e iscrizione alla preload list di Chrome (hstspreload.org).
- **CSP (Content-Security-Policy)**: Header HTTP che dichiara quali sorgenti sono autorizzate per script, style, img, connect, ecc. Mitigation primaria contro XSS reflected e DOM-based. Direttive principali: `default-src`, `script-src`, `style-src`, `img-src`, `connect-src`, `frame-ancestors`, `report-uri`.
- **Forward secrecy**: Proprieta\' del protocollo TLS per cui la compromissione della chiave privata del server NON permette di decifrare le sessioni passate. Garantita dai cipher con scambio chiavi ephemeral (ECDHE, DHE). Cipher RSA static la perdono. Mozilla SSL Configurator profile Modern e Intermediate la garantiscono entrambi.
- **AEAD (Authenticated Encryption with Associated Data)**: Famiglia di cipher che combina cifratura e autenticazione in una singola operazione, eliminando vulnerabilita\' di tipo padding oracle. Esempi: AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305. Raccomandato a partire da TLS 1.2.
- **OCSP stapling**: Estensione TLS per cui il server presenta al client una risposta OCSP firmata dalla CA, evitando la query OCSP del client (privacy + performance). Direttive: Apache `SSLUseStapling on`, Nginx `ssl_stapling on; ssl_stapling_verify on;`.
- **HTTP/2 / HTTP/3**: Versioni successive di HTTP con multiplexing dei flussi, header compression (HPACK), server push (deprecato), QUIC over UDP per HTTP/3. Apache: `Protocols h2 http/1.1`. Nginx: `listen 443 ssl http2` (sintassi pre-1.25), oppure `http2 on;` (sintassi 1.25+).
- **mod_security / ModSecurity**: WAF (Web Application Firewall) per Apache e Nginx, basato su regole pattern-matching su request/response (CRS = Core Rule Set di OWASP). Mitigation di SQLi, XSS, RCE, scanner detection. Apache: `<IfModule mod_security2.c>`. Nginx: build con `libmodsecurity`.
- **Permissions-Policy**: Header che disabilita API browser non utilizzate (camera, microphone, geolocation, payment, USB, ambient-light, accelerometer, gyroscope). Riduce la superficie d'attacco. Successore di `Feature-Policy` (deprecato). Esempio: `camera=(), microphone=(), geolocation=()`.
- **X-Frame-Options / frame-ancestors**: X-Frame-Options (legacy): `DENY` | `SAMEORIGIN` | `ALLOW-FROM origin`. Mitigation contro clickjacking. CSP `frame-ancestors` e\' la versione moderna piu\' espressiva. Best practice: emettere entrambi, X-Frame come fallback per browser legacy.
- **Referrer-Policy**: Header che controlla cosa viene inviato nell'header Referer durante navigazione cross-origin. Valori comuni: `strict-origin-when-cross-origin` (default moderno), `no-referrer` (massima privacy). Default browser variabile e\' un info leak.
- **rate limiting (Nginx)**: `limit_req_zone` definisce zone di rate limit (rate-key + rate). `limit_req` dentro location applica la zone. Critico su endpoint di autenticazione (login, signup, password reset) per resistere a brute force e credential stuffing.
- **add_header override (Nginx)**: Regola controintuitiva di Nginx: se una `location` contiene anche un solo `add_header`, gli `add_header` del `server` parent vengono ignorati per quella location. Workaround: ripetere gli header in ogni location, oppure usare il modulo `headers-more-nginx-module` (`more_set_headers`).
- **Mozilla SSL Configurator**: Tool ufficiale Mozilla che genera config SSL pronte per Apache, Nginx, HAProxy, ecc., scegliendo fra tre profili: **Modern** (TLS 1.3 only, browser molto recenti), **Intermediate** (TLS 1.2 + 1.3, ampia compatibilita\', default raccomandato), **Old** (legacy, da evitare). URL: `ssl-config.mozilla.org`.

## Domande frequenti sul linter Apache/Nginx

### Sono sysadmin / DevOps con poca esperienza specifica su hardening server. Posso usare questo tool?

Si\'. Per ogni finding trovi descrizione del problema in linguaggio operativo e remediation pronta da copy-paste nella config. La logica del tool ricalca quella dei tool ufficiali (Mozilla SSL Configurator, OWASP Secure Headers Project): gli stessi check che farebbe un cyber esperto, automatizzati. Per aspetti che il linter non copre (cert in scadenza, validation di certificati intermedi, monitoring runtime) usa SSLLabs e Mozilla Observatory in parallelo.

### Cosa significa che il linter è AST-based e perché è meglio di un linter regex?

AST = Abstract Syntax Tree: la config viene parsata in un albero di blocchi e direttive con scope preciso. Il linter sa che `add_header X-Frame-Options DENY` dentro `location /admin` NON si applica al resto del sito. Un linter regex vedrebbe la stringa `X-Frame-Options` ovunque nel testo e direbbe "presente". Quel falso negativo ha conseguenze pratiche: l'header e\' presente formalmente ma non e\' emesso sulle response che dovevano protegerlo. Stesso ragionamento per HSTS, CSP, e per la regola `add_header` override Nginx.

### Posso testare un .htaccess o serve l'intero VirtualHost?

Entrambi funzionano. Un `.htaccess` e\' una config Apache parziale (ereditata dal vhost padre): il linter accetta direttive bare al top-level. Un `VirtualHost` completo aggiunge il contesto (porta SSL, certificati). Per audit accurato preferisci il vhost completo perche\' alcuni check (HSTS scoped al vhost SSL, listen 80 redirect) richiedono il blocco. Se incolli solo un .htaccess, il linter non puo\' decidere se sei su HTTPS o HTTP.

### Il sample Apache passa con score 100? Lo voglio capire come baseline.

Il sample Apache include due vhost: uno HTTP->HTTPS redirect, uno HTTPS con SSL/TLS modern, HSTS preload, CSP con report-uri, X-Frame, X-Content-Type, Referrer, Permissions, OCSP stapling, HTTP/2 (Protocols h2), AllowOverride None su Directory. Score atteso: 90-100. Eventuale calo: mod_security non visibile (info, -1), nessun ServerTokens dichiarato esplicitamente (info, -1).

### Override semantica add_header Nginx: come la fixo davvero?

Tre approcci. (1) **Ripeti gli header in ogni location**: piu\' boilerplate ma deterministico, lo capisce qualsiasi sysadmin che legga la config. (2) **Usa `more_set_headers`** del modulo `headers-more-nginx-module`: NON soggetto alla regola override, set globale che si applica anche alle location. Richiede build custom o pacchetto ufficiale (Debian: `libnginx-mod-http-headers-more-filter`). (3) **Refactor della struttura location**: collassa location simili in un'unica con `map` o `if`, riducendo la superficie di override.

### CSP con 'unsafe-inline': quando si può accettare?

Idealmente mai in nuovi progetti: nonce-based o hash-based CSP sono la baseline moderna. Nei casi legacy: (a) frontend con migliaia di inline event handler che richiedono refactor lungo, accetta unsafe-inline per il momento ma documentalo nel commit message della config; (b) tool di analytics che inietta inline script (Google Tag Manager pre-2023, alcuni A/B testing tool), unsafe-inline e\' la via piu\' rapida. Mitigation parziale: aggiungi `'self'` + nonce per gli script tuoi e accetta unsafe-inline solo come fallback whitelist.

### HSTS preload: vale la pena iscriversi alla preload list di Chrome?

Si\' per qualsiasi dominio web-only stabile. La preload list integra il dominio nel codice di Chromium (e dei browser derivati): la prima visita al dominio e\' gia\' forzata HTTPS, eliminando la finestra di first-visit downgrade attack. Trade-off: una volta iscritto, riposi solo HTTPS (no rollback rapido a HTTP). Procedura: `max-age=31536000` minimo, `includeSubDomains` obbligatorio, `preload` obbligatorio, sottometti su `hstspreload.org`.

### /server-status e /nginx_status: vanno disabilitati o solo restricted?

Restricted, non disabilitati: sono utili per monitoring (Nagios, Zabbix, custom dashboard). Restrizione tipica: Apache `<Location /server-status> Require local </Location>` o `Require ip 10.0.0.0/8`. Nginx `location /nginx_status { stub_status on; allow 127.0.0.1; allow 10.0.0.0/8; deny all; }`. Esposti pubblicamente perdono header internal, traffic per-vhost, request rate: information leakage utile per fingerprinting e per riconoscere ondate di attacco.

### TLSv1 e TLSv1.1: vanno completamente disabilitati o e\' OK negoziarli per compatibilita\'?

Completamente disabilitati per qualsiasi nuovo progetto. PCI DSS 4.0 richiede TLSv1.2 minimo da metà 2024. Browser support: TLSv1.2 e\' supportato da IE 11 in poi (Win 7+), Android 5+, iOS 5+. La compatibilita\' rimasta richiesta da TLSv1/TLSv1.1 sono client legacy esoterici (printer enterprise vintage, scada systems): se ce li hai, isolali su un endpoint separato e dichiara TLSv1.2+ ovunque.

### Forward secrecy: quanto è critico in pratica?

Critico per dati a lunga vita conservativa. Senza forward secrecy, una compromissione futura della chiave privata (server breach, key theft, court order) permette di decifrare TUTTE le sessioni TLS passate intercettate (registrate da un avversario passivo come ISP o nation-state actor). Con forward secrecy, le sessioni passate restano cifrate. Cipher con ECDHE/DHE la garantiscono, RSA static no. Best practice: il SSLCipherSuite Mozilla Intermediate la garantisce, migra verso quello.

### HTTP/2 vs HTTP/3: serve abilitare entrambi?

HTTP/2 e\' baseline moderna (deploy mature dal 2018, supporto browser ~99%). HTTP/3 (over QUIC) e\' next-gen ma deploy non triviale: richiede UDP open lato firewall, Apache lo supporta solo con mod_http2 sperimentale, Nginx richiede `--with-http_v3_module` (1.25+). Roadmap pragmatica: HTTP/2 sempre, HTTP/3 quando hai un caso d'uso reale (mobile-heavy, dispositivi con connessioni lossy).

### mod_security: vale la pena attivarlo?

Si\', per qualsiasi sito esposto pubblicamente. Cost: ~5-10% overhead CPU con CRS standard. Beneficio: blocco automatico di SQLi, XSS, RCE, scanner ricognoscibili (nikto, sqlmap, dirb), enumeration, attack pattern in chiaro. Caveat: configurazione iniziale richiede tuning per ridurre falsi positivi sull'app specifica. Alternativa moderna: WAF cloud (Cloudflare, AWS WAF, Sucuri). Costa ma elimina il tuning.

### Posso fare audit di config che usano Include / include verso file esterni?

Il tool linta solo il testo che gli incolli. `Include` Apache e `include` Nginx puntano a file esterni: il browser non puo\' risolverli. Workaround: concatena manualmente i file che ti interessano e incolla il blob risultante, oppure linta i file uno per uno. Per audit completo serve accesso al filesystem del server, fuori scope per un tool browser-only.

### Posso fare audit del file /etc/nginx/nginx.conf principale?

Si\', il parser supporta correttamente `events { }`, `http { }`, `server { }` annidati, `upstream`, direttive top-level. Findings tipici di nginx.conf principale: `server_tokens off` a livello http, `limit_req_zone` globali, ssl session cache. Findings per-server appariranno per ogni `server { }` incluso (anche via include risolti manualmente).

### Privacy: la config che incollo viene salvata o tracciata?

No. Il tool gira interamente nel browser. Nessuna richiesta di rete con la config: parser, regole context-aware, value validators, rendering, generazione del report - tutto in JavaScript locale. Verificabile aprendo il pannello Network di DevTools durante il lint: zero richieste outgoing con i dati della config. La config non viene salvata in `localStorage` né tracciata in analytics.

### Posso integrare il linter in pipeline CI/CD?

Per CI/CD usa tool dedicati: `nginx-config-formatter` + `configtest` di Nginx, `apachectl configtest` di Apache, `gixy` (Yandex, Python) per security audit Nginx, `apache-config-lint` Ruby. Il nostro tool e\' browser-based: ottimo per review interattive, sub-ottimale per pipeline. Caso d'uso valido: code review di un PR di config, lo sviluppatore incolla il diff e fa il triage prima di push.

---
Uno strumento di Maurizio Fonte, senior backend engineer. Tutti gli strumenti: https://www.mauriziofonte.it/strumenti/
