Caddy, HSTS e security.txt
Modulo 7: Dominio, server web e https · Tempo di lettura: 12 minuti
Obiettivo della lezione: Dopo questa lezione saprà usare Caddy come server web semplice con https automatico, impostare HSTS e i principali header di sicurezza (in Caddy e in nginx) senza rendere il Suo sito irraggiungibile, e pubblicare un security.txt valido.
Concetti chiave: Caddy, Caddyfile, https automatico, reverse_proxy, file_server, header, HSTS (Strict-Transport-Security), max-age, includeSubDomains, preload, X-Content-Type-Options, frame-ancestors, Referrer-Policy, security.txt, Contact, Expires, /.well-known/
Caddy: https senza pensieri
Nelle lezioni 7.2 e 7.3 ha creato con nginx e certbot un sito con https. Si tratta di due programmi, alcuni file e un timer. Caddy fa tutto in uno: è un server web con un client ACME integrato. Se un nome è presente nella configurazione, punta al server e le porte 80 e 443 sono raggiungibili, Caddy ottiene da solo un certificato, lo rinnova in tempo e reindirizza http verso https.
Caddy è presente nei repository dei pacchetti di Debian e Ubuntu (in una versione un po' più vecchia); gli sviluppatori offrono anche un proprio repository apt con la versione più recente, con una propria chiave e Signed-By come nella lezione 4.1. Nel modulo 9 Caddy viene eseguito come container per i Suoi servizi Docker (lezione 9.4). Qui lo usa come un normale servizio.
anna@web1:~$ sudo apt install caddy
anna@web1:~$ systemctl status caddyUsi nginx oppure Caddy sulle porte 80 e 443, non entrambi: un solo programma alla volta può restare in ascolto su una porta.
Il Caddyfile
La configurazione si trova in /etc/caddy/Caddyfile. Un sito statico e un'applicazione dietro un reverse proxy:
example.com, www.example.com {
root * /var/www/example.com
file_server
encode zstd gzip
}
app.example.com {
reverse_proxy 127.0.0.1:3000
}È tutto qui. Caddy resta in ascolto automaticamente su IPv4 e IPv6, richiede i certificati per i tre nomi, reindirizza http verso https e con reverse_proxy inoltra da solo gli header X-Forwarded-For e X-Forwarded-Proto (ciò che in nginx ha fatto a mano, lezione 7.2).
Il test e il ricaricamento funzionano come con nginx:
anna@web1:~$ caddy validate --config /etc/caddy/Caddyfile
Valid configuration
anna@web1:~$ sudo systemctl reload caddy
anna@web1:~$ sudo journalctl -u caddy -fNel journal vede il recupero dei certificati. Se qualcosa va storto, lì trova il motivo: di solito lo stesso che con certbot (porta 80 chiusa, nome che punta altrove, IPv6 non funzionante; lezione 7.3).
HSTS: far ricordare al browser che si tratta di https
Il reindirizzamento da http a https ha un punto debole: la primissima richiesta via http viaggia ancora non cifrata. Qualcuno sulla stessa rete può intercettarla e trattenere il visitatore su http. HSTS (HTTP Strict Transport Security, RFC 6797) risolve questo problema. Il Suo sito invia via https questo header:
Strict-Transport-Security: max-age=31536000Il browser ricorda allora per un anno (31.536.000 secondi) che questo nome è accessibile solo via https. Se in seguito il visitatore digita http://, il browser lo trasforma da solo in https, ancora prima che qualcosa passi sulla rete. Un header HSTS ricevuto via http viene ignorato dal browser; vale solo via https.
C'è un rovescio della medaglia. Se un browser ha memorizzato HSTS e rileva un errore del certificato (scaduto, nome errato), il visitatore non ha alcun pulsante per procedere comunque. Il Suo sito resta quindi irraggiungibile per quei visitatori finché il certificato non è corretto. Per questo:
- Attivi HSTS solo quando https funziona ovunque e il rinnovo avviene automaticamente (lezione 7.3).
- Inizi con un
max-agebreve, per esempio un giorno (86400), e lo aumenti per gradi fino a un anno. - Faccia attenzione con
includeSubDomains: vale per ogni sottodominio, anche per un vecchio sottodominio con un dispositivo o un servizio senza certificato valido. preloadchiede l'inserimento in un elenco integrato nei browser (hstspreload.org). Per questo si richiedono tra l'altro unmax-agedi almeno un anno,includeSubDomainse https su tutti i sottodomini. Uscire dall'elenco richiede mesi. Lo faccia solo se è certo che l'intero dominio resterà per sempre in https.
Gli altri header di sicurezza
Oltre a HSTS esistono alcuni header che con poco sforzo aiutano molto:
| Header | Contro che cosa | Valore con cui iniziare |
|---|---|---|
X-Content-Type-Options | il browser cerca di indovinare il tipo di file, per cui un'"immagine" caricata può essere eseguita come script | nosniff |
Content-Security-Policy: frame-ancestors (o il più vecchio X-Frame-Options) | clickjacking: un altro sito carica la Sua pagina in modo invisibile in un frame | frame-ancestors 'self' (o X-Frame-Options: SAMEORIGIN) |
Referrer-Policy | l'indirizzo della Sua pagina (con termini di ricerca o numeri d'ordine) finisce ad altri siti | strict-origin-when-cross-origin |
Un Content-Security-Policy completo (quali script e stili possono essere caricati) va costruito su misura per ogni sito ed esula da questo corso; inizi solo con frame-ancestors.
In Caddy li imposta con la direttiva header nel blocco di un sito:
example.com, www.example.com {
root * /var/www/example.com
file_server
header {
Strict-Transport-Security "max-age=31536000"
X-Content-Type-Options "nosniff"
Content-Security-Policy "frame-ancestors 'self'"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
}Caddy non imposta da solo HSTS né questi header; deve quindi inserirli Lei. -Server rimuove l'header Server. Nella lezione 9.4 imposterà in un blocco dello stesso tipo un Suo header X-Weboke-Cursus per l'esercizio.
In nginx inserisce le stesse righe nel blocco server per la porta 443:
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;always fa sì che vengano inviati anche con le pagine di errore. Attenzione a un noto tranello di nginx: se in un blocco location compare anche un solo add_header, le righe add_header del blocco server non valgono più per quella location. Per questo verifichi sempre il risultato:
anna@laptop:~$ curl -sI https://example.com | grep -iE 'strict|nosniff|frame|referrer'
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
content-security-policy: frame-ancestors 'self'
referrer-policy: strict-origin-when-cross-originsecurity.txt: così qualcuno può segnalarLe una vulnerabilità
Supponga che qualcuno trovi una vulnerabilità sul Suo server, per esempio una cartella aperta o un servizio obsoleto. Come fa questa persona a sapere chi avvisare? Per questo esiste security.txt (RFC 9116): un piccolo file di testo in una posizione fissa, https://<jouwdomein>/.well-known/security.txt.
Contact: mailto:security@example.com
Expires: 2027-10-31T23:00:00Z
Preferred-Languages: nl, en
Canonical: https://example.com/.well-known/security.txtLe regole:
Contactè obbligatorio: un indirizzomailto:,https://otel:a cui arrivano le segnalazioni. Usi un indirizzo che qualcuno legge davvero.Expiresè obbligatorio e può comparire una sola volta: la data dopo la quale il file è considerato obsoleto. La RFC consiglia una data entro un anno. In questo modo non resta online un file con un indirizzo dimenticato da tempo. Segni in agenda quando deve prolungarla.Preferred-Languages,CanonicalePolicy(un link alla Sua policy per le segnalazioni) sono facoltativi.- Il file deve essere servito via https, come testo semplice (
text/plain, UTF-8). La vecchia posizione/security.txtè ammessa come aggiunta, ma/.well-known/ha la precedenza.
Pubblicarlo per un sito statico:
anna@web1:~$ sudo mkdir -p /var/www/example.com/.well-known
anna@web1:~$ sudoedit /var/www/example.com/.well-known/security.txt
anna@laptop:~$ curl -sI https://example.com/.well-known/security.txt | grep -i content-type
content-type: text/plain; charset=utf-8Se in nginx usa la regola di riserva location ~ /\. { deny all; } della lezione 7.2, inserisca prima un'eccezione: location ^~ /.well-known/ { }. Per un'applicazione dietro un reverse proxy può far puntare in Caddy il percorso /.well-known/security.txt a un file con un blocco handle e file_server.
Un errore frequente: un sito o un'applicazione che risponde a ogni percorso sconosciuto con la home page e lo stato 200. In quel caso security.txt "esiste", ma è HTML. Verifichi quindi anche il contenuto.
Su AlmaLinux e Rocky Linux
Lì Caddy proviene dal repository degli sviluppatori oppure da EPEL/COPR. Come per nginx, SELinux deve consentire un reverse proxy (setsebool -P httpd_can_network_connect 1). Il Caddyfile e gli header sono gli stessi.
Riepilogo
- Caddy gestisce da solo certificati, rinnovo e reindirizzamento verso https;
reverse_proxyinoltra automaticamente gli header corretti. - HSTS fa ricordare ai browser che il Suo sito è solo https; aumenti
max-agegradualmente, faccia attenzione conincludeSubDomainse moltissima attenzione conpreload. - Imposti inoltre
X-Content-Type-Options: nosniff,frame-ancestors 'self'e unReferrer-Policy; in Caddy conheader, in nginx conadd_header ... always, e verifichi concurl -I. - security.txt si trova in
/.well-known/security.txt, via https, come testo semplice, conContactobbligatorio e un soloExpiresentro un anno.
Quiz
Esercizio
Esercizio Z7.4: HSTS, header e security.txt. Imposti per il Suo sito HSTS (almeno 180 giorni, dopo che https funziona bene da un po' di tempo), X-Content-Type-Options: nosniff e frame-ancestors 'self' (o X-Frame-Options), e pubblichi un security.txt con Contact e un Expires entro un anno. Inserisca il Suo hostname. Il programma recupera https://<hostnaam>/ e verifica gli header, poi recupera https://<hostnaam>/.well-known/security.txt e verifica i campi. Non salva nulla oltre al risultato e alla data di Expires.
Per approfondire
- Intestazioni HSTS e di sicurezza per il Suo sito web
- Caddy, Automatic HTTPS: https://caddyserver.com/docs/automatic-https
- Caddy, direttiva header: https://caddyserver.com/docs/caddyfile/directives/header
- RFC 6797, HTTP Strict Transport Security: https://www.rfc-editor.org/rfc/rfc6797.html
- Elenco di preload HSTS e requisiti: https://hstspreload.org/
- RFC 9116, security.txt: https://www.rfc-editor.org/rfc/rfc9116.html
- securitytxt.org (creare e verificare): https://securitytxt.org/
