Nella parte 1, abbiamo fatto un rapido tour di S/MIME, esaminando la firma e la crittografia dei nostri flussi di messaggi attraverso una gamma di client di posta. Parte 2 ci ha portato attraverso un semplice strumento da riga di comando per firmare e crittografare e-mail, quindi inviarle tramite SparkPost. La parte 3 ha mostrato come iniettare flussi di posta sicuri in piattaforme on-premises come Port25 PowerMTA e Momentum.
In questa serie, abbiamo visto come includere una firma S/MIME sia abbastanza semplice. Inviare e-mail crittografate S/MIME è più complesso perché è necessario ottenere le chiavi pubbliche del destinatario. È una cosa quando stai usando un client di posta per umani come Thunderbird – ma come può funzionare con flussi di e-mail generati da app?
Ma aspetta – c'è un altro modo per entrare a Mordor e ottenere quelle chiavi. Il tuo servizio può invitare i tuoi clienti (via e-mail, naturalmente) a inviarti un'e-mail firmata a un indirizzo di assistenza clienti noto. Utilizzando i poteri magici dei webhook di SparkPost Inbound Relay, estrarremo e memorizzeremo quella chiave pubblica per te da utilizzare.
Possiamo riassumere questo in un semplice caso d'uso:
Come destinatario di messaggi, fornisco al tuo servizio la mia firma e-mail personale tramite e-mail, in modo che in futuro le e-mail possano essere inviate a me in forma crittografata S/MIME.
Da questo, possiamo derivare alcuni requisiti più dettagliati:
Abbiamo bisogno di un servizio e-mail in entrata sempre attivo e affidabile per ricevere quelle e-mail firmate.
Non ci dovrebbero essere requisiti speciali sul formato dell'e-mail, se non che dovrebbe contenere una firma S/MIME.
Poiché chiunque può provare a inviare un'e-mail a questo servizio, dovrebbe essere progettato in modo difensivo, ad esempio, per rifiutare messaggi “falsificati” da attori malintenzionati. Ci dovrà essere diversi strati di controllo.
Se tutto va bene, il servizio memorizzerà il certificato in un file, utilizzando il noto formato di Privacy-Enhanced Mail in testo semplice (PEM).
Ci sono alcuni requisiti non funzionali:
I servizi webhook macchina-a-macchina possono essere difficili da vedere solo dalle risposte su ciò che sta accadendo all'interno. Il servizio dovrebbe fornire ampi registri dell'applicazione leggibili dall'uomo. In particolare, l'analisi e il controllo dei certificati dovrebbero essere registrati.
Aggiungiamo casi di test per gli interni dell'app, utilizzando il bel Pytest framework, e eseguiamo automaticamente quei test al momento del check-in utilizzando l'integrazione Travis CI con GitHub.
OK – cominciamo!
1. Panoramica della soluzione
Ecco come apparirà la soluzione complessiva.
2. Installazione, configurazione e avvio dell'app web
Inizieremo con questa parte, così la avremo completamente testata prima di collegare i webhook del relay in entrata.
L'app web è inclusa nello stesso progetto GitHub delle parti 1 – 3, quindi se hai seguito quelle parti, ce l'hai già. Ecco i nuovi elementi:
Programma readSMIMEsig.py – leggi un'e-mail e analizza i certificati intermedi e utente.
Programma webapp.py – semplice applicazione web compatibile con Flask per l'uso con i webhook di SparkPost Inbound Relay.
webapp.ini – file di configurazione per quanto sopra. Un file di configurazione consente di passare facilmente gli stessi valori sia per le applicazioni da riga di comando che per le applicazioni web.
Devi assicurarti che il tuo host abbia aperto il corretto numero di porta TCP per le richieste in entrata dal mondo esterno affinché SparkPost possa POSTare messaggi nella tua app. Se sei ospitato su AWS EC2, ad esempio, dovrai configurare il Gruppo di Sicurezza della tua istanza.
Istruzioni per configurare e avviare l'app web sono date qui – è piuttosto facile. Per controllare se la tua app è in esecuzione e accessibile dal mondo esterno, puoi inviare richieste (vuote) da un altro host usando curl, ad esempio:
curl -X POST https://app.trymsys.net:8855/
Dovresti vedere una risposta come:
{"message":"Unknown Content-Type in request headers"}
Questa è una buona cosa – la tua app è in esecuzione!
Nel webapp.log sul tuo host, vedrai un output simile a questo:
2019-01-15 00:11:07,575,root,INFO,Richiesta da 38.96.5.10,scheme=https,path=/ 2019-01-15 00:11:07,575,root,INFO,| len(headers)=3,len(body)=None 2019-01-15 00:11:07,575,root,INFO,| Unknown Content-Type: None
Per aiutarti a lavorare con dati reali nella tua app immediatamente, puoi importare questa specifica richiesta di Postman dal repository del progetto. Questo simula ciò che il tuo account SparkPost farà, cioè invia un POST https contenente un'e-mail con un certificato specifico e valido (appartenente a un mio account di test) alla tua app.
Devi solo cambiare l'indirizzo di destinazione nella richiesta (nella casella grigia sopra) per adattarlo alla tua installazione. Se hai cambiato il valore del token in webapp.ini, adatta il valore dell'intestazione in Postman di conseguenza.
Se la tua app funziona, vedrai una risposta “200 OK” di ritorno in Postman. Il file di log webapp.log del tuo host conterrà un output come questo:
2019-01-15 00:11:48,554,root,INFO,Richiesta da 38.96.5.10,scheme=https,path=/ 2019-01-15 00:11:48,554,root,INFO,| len(headers)=10,len(body)=14778 2019-01-15 00:11:48,555,root,INFO,| msg_from=bob.lumreeker@gmail.com,rcpt_to=secureme@inbound.thetucks.com,len(email_rfc822)=9223 2019-01-15 00:11:48,599,root,INFO,| from=bob.lumreeker@gmail.com,DKIM passato 2019-01-15 00:11:48,600,root,INFO,| content-type=multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="------------ms010908020707040304020406",content-description=None 2019-01-15 00:11:48,600,root,INFO,| content-type=text/plain; charset=utf-8; format=flowed,content-description=None 2019-01-15 00:11:48,600,root,INFO,| content-type=application/pkcs7-signature; name="smime.p7s",content-description=Firma crittografica S/MIME 2019-01-15 00:11:48,600,root,INFO,| filename=smime.p7s,bytes=3998 2019-01-15 00:11:48,601,root,INFO,| Certificato: subject email_address=['bob.lumreeker@gmail.com'],not_valid_before=2018-10-03 00:00:00,not_valid_after=2019-10-03 23:59:59,hash_algorithm=sha256,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Client Authentication and Secure Email CA'} 2019-01-15 00:11:48,602,root,INFO,| Certificato: subject email_address=[],not_valid_before=2013-01-10 00:00:00,not_valid_after=2028-01-09 23:59:59,hash_algorithm=sha384,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Certification Authority'} 2019-01-15 00:11:48,616,root,INFO,| file scritto ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True
Per un rapido controllo di sanità, cerca l'ultima riga – se dice “file scritto”, sei a posto. Il resto di questo mostra il controllo DKIM e il processo di validazione del certificato.
3. Configurazione dei webhook di relay in entrata di SparkPost
Per prima cosa, selezioniamo un dominio da utilizzare come indirizzo per i messaggi in entrata – qui, sarà inbound.thetucks.com. Imposta il tuo dominio seguendo questa guida. Ecco i passaggi che ho usato in dettaglio:
3.1 Aggiungi record MX
Avrai bisogno di accesso al tuo specifico account del fornitore di servizi Internet. Una volta fatto, puoi controllarli con dig – ecco il comando per il mio dominio.
dig +short MX inbound.thetucks.com
Dovresti vedere:
10 rx3.sparkpostmail.com. 10 rx1.sparkpostmail.com. 10 rx2.sparkpostmail.com.
3.2 Crea un dominio in entrata
Usa la collezione API di Postman di SparkPost, selezionando la chiamata Inbound Domains / Create .. Il corpo della richiesta POST contiene il tuo dominio, ad esempio:
{ "domain": "inbound.thetucks.com" }
3.3 Crea un webhook di relay
Crea un webhook di relay in entrata utilizzando la chiamata Postman pertinente. Il corpo del messaggio nel mio caso contiene:
{ "name": "Webhook di raccolta certificati", "target": "https://app.trymsys.net:8855/", "auth_token": "t0p s3cr3t t0k3n", "match": { "protocol": "SMTP", "domain": "inbound.thetucks.com" } }
Come accennato prima, ti consiglio di impostare un auth_token con un valore segreto a tua scelta, come impostato nel file webapp.ini sul tuo host.
Il tuo valore “target” deve corrispondere al tuo indirizzo host e alla porta TCP dove ospiterai l'app web.
Il tuo valore “domain” deve corrispondere ai tuoi record MX impostati nel passo 1.
Ecco fatto! La parte tecnica è completata. Ora dovresti essere in grado di inviare certificati al tuo indirizzo in entrata, saranno elaborati e appariranno sul tuo host dell'app web – in questo caso, un file denominato bob.lumreeker@gmail.com.crt.
Ora puoi inviare e-mail crittografate a Bob, utilizzando gli strumenti descritti nelle parti 2 e 3 di questa serie.
Puoi esaminare il contenuto di un certificato usando:
openssl x509 -inform PEM -in bob.lumreeker\@gmail.com.crt -text -noout
4. Interni: verifica DKIM, validazione del certificato
L'app controlla che le e-mail ricevute abbiano un DKIM valido e verifica che i certificati stessi siano validi, come descritto qui. Ci sono anche note di implementazione e idee per ulteriori lavori.
Riassumendo…
Abbiamo visto come le chiavi pubbliche dei destinatari possano essere raccolte facilmente utilizzando un'e-mail a un indirizzo di webhook del relay in entrata. Una volta fatto, quei destinatari possono ricevere i loro messaggi in forma crittografata S/MIME.
Questo è tutto per ora! Buon invio.