Https everywhere: perché non metterlo su tutti i progetti?
Nei seguenti esempi si suppone di voler ottenere un certificato ssl per il dominio www.example.com.
SNI: Server Name Indication
Nel protocollo ssl standard, un pacchetto contenente delle informazioni criptate arriva al server tramite un indirizzo IP. Il server utilizza il certificato ssl associato a all’istanza del server su quell’indirizzo IP e stabilisce la connessione. La comunicazione è sicuramente criptata, ma potremmo essere arrivati a quell’IP tramite un altro nome di dominio.
Il classico esempio è quando abbiamo un certificato ssl per www.example.com e permettiamo anche a example.com di raggiungere il server. Digitando quest’ultimo ci troveremo di fronte ad un alert:
Ora, se sei un nerd stile me, apri il certificato, noti che il problema era solo un errata configurazione dei DNS e prosegui, ma un utente medio che visita il portale della propria banca magari si farà qualche problema e chiuderà la finestra.
Supponiamo quindi che il nostro sistema preveda un’unica istanza di server in ascolto su un certo indirizzo IP con un unico certificato ssl da fornire. N domini significherebbero N indirizzi IP, cosa non sempre realizzabile, almeno finché non avremo IPV6 ovunque.
Per ovviare a questo limite i tutti browser recenti hanno implementato un nuovo protocollo: l’SNI. In questa nuova modalità il browser manda in chiaro l’hostname a cui vuole connettersi. Nel sistema standard l’hostname sta negli header della richiesta, che sono criptati. A questo punto possiamo avere anche molti server in ascolto con hostname differenti sullo stesso indirizzo IP: avere in chiaro l’hostname ci permette di ricevere il certificato corretto.
Tutto molto bello, tranne per una piccola cosa: i browser più vecchi non sanno gestire questo tipo di ssl (ma stiamo parlando di browser per symbian e browser per Blackbarry OS7 o precedente.)
Cloudflare
Cloudflare offre una soluzione universale per la gestione di certificati SSL (in particolare si potrà utilizzare come alternativa a tutti i casi che affronteremo in questo articolo).
Cloudflare è una CDN che viene utilizzata per effettuare un caching delle pagine. Per configurarla è necessario che il record DNS di www.example.com punti verso le macchine della CDN. Poi si istruisce la CDN su quale sia l’indirizzo del server che ospita il nostro sito/applicazione.
Il gioco sta tutto qui: essendo il nome di dominio collegato direttamente alla CDN sarà lei stessa a doverci fornire il certificato ssl.
Supponendo di voler mettere una CDN davanti ad un sito hostato su Amazon S3 sono necessari i seguenti step:
- Trasferire la gestione del DNS a Cloudflare (bisogna andare nella dashboard del register del dominio e settare come server DNS quelli di Cloudflare
- Nel pannello di configurazione DNS di Cloudflare settiamo la normale regola DNS verso il server (record A o CNAME verso il server effettivo)
- Nel pannello Crypto di Cloudflare abilitare l’Https verso il client.
Dal momento che abbiamo spostato la gestione DNS del nostro dominio su Cloudflare, abbiamo dato la garanzia di essere gli effettivi amministratori del dominio, condizione sufficiente per poter ricevere un certificato ssl.
A questo punto abbiamo un certificato valido dal browser a Cloudflare, lui internamente gestisce la comunicazione con il server originale.
Come si può notare non è stato fatto alcun intervento lato server, e questo è il grande vantaggio di questa architettura. Il problema principale di questa architettura è la necessità di trasferire a Cloudflare la gestione del DNS, cosa che, in particolare quando il dominio non è di propria proprietà, è molto difficile realizzare.
Siti Statici su Amazon S3
Amazon S3 offre la funzionalità di hostare nei suoi bucket pagine HTML, permettendo di avere una sorta di server web per file statici. Nel caso di Cantiere, generiamo i siti statici tramite Middleman e il nostro CMS per siti statici DatoCMS.
Il mondo di AWS comprende un servizio di Certification Authority che rilascia certificati ssl da utilizzare internamente alla piattaforma: Amazon Certificate Manager.
Per generare un certificato è sufficiente fornire il nome del dominio. Mentre Cloudflare da per scontato che sia l’admin del dominio a settare il DNS resolver, Amazon non possiede informazioni a priori per la certificazione: l’autenticazione dell’admin del dominio avviene tramite una email mandata ad un set di indirizzi noti (admin@example.com, administrator@example.com) e a quelli dell’Admin rilevabili dal servizio whois. All’interno di questa mail c’è un link di attivazione: seguite il link e Certificate Manager considererà questo HIT come prova di essere admin del dominio.
Ottenuto il certificato, non sarà possibile utilizzarlo con S3 direttamente. Dobbiamo quindi attivare una distribuzione di AWS Cloudfront, il servizio di CDN interno.
Una volta che è stata creata la distribuzione impostiamo l’url pubblico del bucket (mybucket.s3-website-eu-west1.amazonaws.com) come Origin, nella sezione General scegliamo il certificato precendentemente creato da Certificate Manager e in Behaviour impostiamo una Policy (a meno di esigenze particolari, la Policy HTTP => HTTPS va più che bene).
Rispetto a Cloudflare, qui abbiamo il vantaggio di non dover essere i gestori del dominio. È sufficiente che l’admin segua il link nella mail per ottenere un certificato valido, ma la cosa, anche se contenuto, ha un certo costo; Cloudflare offre il servizio nel piano Free, Cloudfront invece ha sempre un costo proporzionale alla banda trasferita.
Server personale
Nel caso in cui si abbia la necessità di avere un server personale (ad esempio DigitalOcean o Linode) possiamo sfruttare il protocollo ACME tramite il servizio LetsEncrypt.
Acme è un protocollo che automatizza la generazione e il rinnovo dei certificati ssl. Il meccanismo è molto banale:
- Il client richiede al server ACME una richiesta per ottenere un certificato per un dominio.
- ACME risponde alla richiesta con un challenge, composto da un filename e un contenuto.
- Il client predispone il server affinché al path richiesto da ACME sia presento il contenuto atteso.
- Il client dice ad ACME di verificare la richiesta.
- ACME va all’indirizzo www.example.com/filename e controlla se il contenuto è quello voluto.
- Se la verifica avviene con successo, il client richiede il certificato e ACME fornisce un certificato completo (certificato, chiave privata, chain e fullchain).
Come si può notare client e server potrebbero benissimo essere sia la stessa macchina che due macchine differenti. L’unica garanzia che ACME vuole è che il richiedente del certificato dimostri di avere accesso in scrittura sulla macchina associata al dominio da certificare.
Una guida completa alla configurazione su un server è disponibile a questo link.
Nel caso di server personale questo permette di avere fisicamente dei certificati ssl senza tutte le problematiche associate ai classici Certificatori (costi, complessità nell’autenticazione del gestore del dominio). Ovviamente sarà nostra cura gestire lo scheduling della procedura di rinnovo, ma avendo già accettato di farsi carico della sistemistica di un server personale il costo di gestione dei certificati, a mio parere, è esiguo.
Heroku Platform
La piattaforma Heroku è sempre stata un punto di riferimento per il deploy delle applicazioni Rack. Niente oneri sistemistici: ogni app ha un repository git, si imposta questo repository come remote e con un push si deploya l’applicazione (Heroku spacchetta il repo e tira su tutto l’occorrente per eseguire quel tipo di app).
L’ssl su Heroku è stato da sempre oggetto di dibattito. Essendo una piattaforma Cloud non è dato sapere a priori l’indirizzo IP della macchina, dato che viene gestito dalla loro infrastruttura. A differenza di Cloudflare o AWS, non forniscono un certificato creato da loro, ma tutto è protetto dal loro certificato che copre i domini .herokuapp.com.
Le soluzioni erano solo 2:
- Cloudflare davanti ad Heroku
- Comprarsi un certificato da terze parti e abilitare il plugin Heroku che forniva l’Endpoint necessario a fornire quel certificato ssl (alla modica cifra di 20$/mese, più il prezzo del certificato).
Da qualche mese è stato abilitato il supporto SNI gratuitamente sulla piattaforma (a patto che si utilizzi un Dyno a pagamento), il che porta un bel vantaggio economico.
A questo punto viene da chiedersi: posso usare un certificato Let’s Encrypt su Heroku?
Abbiamo spiegato in precedenza che il sistema Let’s Encrypt non obbliga il client che deve ottenere il certificato ad essere fisicamente sul server che si dovrà certificare: basta dimostrare di poter generare contenuti sotto il dominio in questione.
L’idea è dunque di avere un’architettura così composta:
- Un processo sotto Heroku Scheduler che inizia la procedura di negoziazione con il server ACME e setta i relativi challenge in alcune variabili di ambiente;
- Un componente che cattura le richieste lato applicazione e, se riconosce la richiesta del challenge, risponde con il codice atteso da ACME;
- Il processo iniziale chiede il certificato ed infine effettua l’upload nel relativo progetto Heroku tramite Api.
Esistono 2 soluzioni specifiche per risolvere questo problema:
L’unica cosa di cui tenere conto è la seguente: dal momento che si decide di utilizzare un certificato custom dobbiamo cambiare l’impostazione del DNS. Prima il DNS aveva questa regola
www.example.com. CNAME my-app.herokuapp.com.
ma questa configurazione fornirà sempre il certificato wildcard per tutto herokuapp.com.
Affinché Heroku serva il nuovo certificato ssl, bisogna utilizzare questa regola
www.example.com. CNAME www.example.com.herokudns.com.
Sabayon
Sabayou è un tool scritto in GO che avvia la procedura di certificazione, setta le variabili di ambiente, lancia il comando di verifica e alla fine fa l’upload del certificato. Questo tool deve stare in un Dyno riservato, il che implica che l’archietttura finale sia composta da 2 applicazioni Heroku: my-app e my-app-sabayon. Il tutto potrà funzionare in quanto my-app-sabayou dovrà possedere un token OAuth per l’account Heroku che ospita my-app.
Dentro my-app invece sarà necessario un piccolo componente (nella guida ci sono tutti gli snippet per i vari tipi di server) da aggiungere nel nostro codice affinché qualcuno usando le variabili di ambiente fornisca i challenge necessari. Di conseguenza si presta a TUTTE le piattaforme (Php, Java, Django, Nodejs ecc).
Let’s Encrypt Rails Heroku
Nel caso invece in cui l’applicazione sia un’app Rails, è possibile utilizzare la gemma in questione, in cui il processo che in sabayou è scritto in Go è sostituito da un task rake che gira internamente.
Https Everywhere
Come abbiamo visto esistono diversi meccanismi per avere delle connessioni sicure che non hanno costo di acquisto di certificati e costi veramente bassi in termini di risorse temporali per configurare gli ambienti.
A questo punto la domanda è diventata “Perché non dovrei mettere sotto HTTPS tutti i miei progetti”? :)
Originally published at www.cantierecreativo.net on March 16, 2017.