Dans la partie 1, nous avons fait une rapide visite de S/MIME, en examinant la signature et le chiffrement de nos flux de messages à travers une gamme de clients de messagerie. La partie 2 nous a conduits à travers un simple outil en ligne de commande pour signer et chiffrer les e-mails, puis les envoyer via SparkPost. La partie 3 a montré comment injecter des flux de mail sécurisés dans des plateformes sur site telles que Port25 PowerMTA et Momentum.
Dans cette série, nous avons vu comment inclure une signature S/MIME est relativement simple. Envoyer un mail chiffré S/MIME est plus complexe car vous devez obtenir les clés publiques des destinataires. C'est une chose lorsque vous utilisez un client de messagerie pour humains tel que Thunderbird – mais comment cela fonctionne-t-il avec des flux d'e-mails générés par des applications ?
Mais attendez – il existe une autre façon d'entrer dans Mordor pour obtenir ces clés. Votre service peut inviter vos clients (par e-mail, bien sûr) à vous renvoyer un mail signé à une adresse de service client connue. En utilisant les pouvoirs magiques des webhooks de SparkPost Inbound Relay, nous allons extraire et stocker cette clé publique pour que vous puissiez l'utiliser.
Nous pouvons résumer cela dans un cas d'utilisation simple :
En tant que destinataire de messages, je fournis à votre service ma signature de courriel personnelle par e-mail, afin que, à l'avenir, les e-mails puissent m'être envoyés sous forme chiffrée S/MIME.
À partir de cela, dérivons quelques exigences plus détaillées :
Nous avons besoin d'un service de messagerie entrant toujours actif et fiable pour recevoir ces e-mails signés.
Il ne devrait y avoir aucune exigence spéciale concernant le format de l'e-mail, si ce n'est qu'il doit porter une signature S/MIME.
Parce que n'importe qui peut essayer d'envoyer un e-mail à ce service, il doit être conçu de manière défensive, par exemple, pour rejeter les messages « usurpés » provenant de mauvais acteurs. Il devra y avoir plusieurs couches de vérification.
Si tout est vérifié correctement, le service stockera le certificat dans un fichier, en utilisant le format bien connu Privacy-Enhanced Mail (PEM) en texte clair.
Il y a certaines exigences non fonctionnelles :
Les services de webhooks machine-à-machine peuvent être difficiles à comprendre uniquement à partir des réponses sur ce qui se passe à l'intérieur. Le service doit fournir des journaux d'application au niveau humain extensifs et lisibles. En particulier, l'analyse et la vérification des certificats doivent être enregistrées.
Nous ajoutons des cas de test pour les internes de l'application, en utilisant le joli Pytest, et exécutons ces tests automatiquement lors du contrôle d'accès à l'aide de l'intégration Travis CI avec GitHub.
OK – commençons!
1. Vue d'ensemble de la solution
Voici à quoi ressemblera la solution dans son ensemble.
2. Installation, configuration et démarrage de l'application web
Nous commencerons par cette partie, afin que nous puissions la tester complètement avant de plomber les webhooks du relais entrant.
L'application web est incluse dans le même projet GitHub que les parties 1 à 3, donc si vous avez suivi ces parties, vous l'avez déjà. Voici les nouvelles parties :
Programme readSMIMEsig.py – lire un e-mail et extraire les certificats intermédiaires et utilisateurs.
Programme webapp.py – application web simple compatible avec Flask pour une utilisation avec les webhooks de SparkPost Inbound Relay.
webapp.ini – fichier de configuration pour ce qui précède. Un fichier de configuration permet de passer facilement les mêmes valeurs à la fois aux applications en ligne de commande et web.
Vous devez vous assurer que votre hôte a le bon numéro de port TCP ouvert pour les demandes entrantes du monde extérieur afin que SparkPost puisse POST des messages vers votre application. Si vous êtes hébergé sur AWS EC2, par exemple, vous devrez configurer le Groupe de sécurité de votre instance.
Les instructions pour configurer et démarrer l'application web sont données ici – c'est assez facile. Pour vérifier que votre application fonctionne et est accessible depuis le monde extérieur, vous pouvez envoyer des demandes (vides) depuis un autre hôte en utilisant curl, par exemple :
curl -X POST https://app.trymsys.net:8855/
Vous devriez voir une réponse telle que :
{"message":"Unknown Content-Type in request headers"}
C'est une bonne chose – votre application fonctionne!
Dans webapp.log sur votre hôte, vous verrez une sortie similaire à celle-ci :
2019-01-15 00:11:07,575,root,INFO,Request from 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
Pour vous aider à jouer avec des données réelles dans votre application immédiatement, vous pouvez importer cette demande spécifique Postman request depuis le dépôt du projet. Cela simule ce que votre compte SparkPost fera, c'est-à-dire qu'il envoie un POST https contenant un e-mail avec un certificat spécifique et valide (appartenant à un de mes test) vers votre application.
Vous devez simplement changer l'adresse cible dans la demande (dans la boîte grise ci-dessus) pour correspondre à votre installation. Si vous avez changé la valeur du jeton dans webapp.ini, ajustez la valeur de l'en-tête dans Postman pour correspondre.
Si votre application fonctionne, vous verrez une réponse "200 OK" dans Postman. Votre fichier webapp.log d'hôte contiendra une sortie comme celle-ci :
2019-01-15 00:11:48,554,root,INFO,Request from 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 passed 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=S/MIME Cryptographic Signature 2019-01-15 00:11:48,600,root,INFO,| filename=smime.p7s,bytes=3998 2019-01-15 00:11:48,601,root,INFO,| Certificate: 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,| Certificate: 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,| written file ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True
Pour un contrôle rapide de la solidité, recherchez la dernière ligne – si elle indique "written file", alors tout va bien. Le reste montre le contrôle DKIM et le processus de validation du certificat.
3. Configuration des webhooks de relay entrant SparkPost
Tout d'abord, nous sélectionnons un domaine à utiliser comme adresse de message entrant – ici, ce sera inbound.thetucks.com. Configurez votre domaine en suivant ce guide. Voici les étapes que j'ai utilisées en détail :
3.1 Ajouter des enregistrements MX
Vous aurez besoin d'accéder à votre compte de fournisseur de services Internet spécifique. Une fois terminé, vous pouvez les vérifier avec dig – voici la commande pour mon domaine.
dig +short MX inbound.thetucks.com
Vous devriez voir :
10 rx3.sparkpostmail.com. 10 rx1.sparkpostmail.com. 10 rx2.sparkpostmail.com.
3.2 Créer un domaine entrant
Utilisez la collection d'API Postman de SparkPost, en sélectionnant l'appel Inbound Domains / Create .. Le corps de la requête POST contient votre domaine, par exemple :
{ "domain": "inbound.thetucks.com" }
3.3 Créer un webhook de relais
Créez un webhook de relais entrant en utilisant l'appel Postman pertinent. Le corps du message dans mon cas contient :
{ "name": "Webhook de collecte de certificats", "target": "https://app.trymsys.net:8855/", "auth_token": "t0p s3cr3t t0k3n", "match": { "protocol": "SMTP", "domain": "inbound.thetucks.com" } }
Comme mentionné auparavant, je recommande de définir un auth_token à votre propre valeur secrète, comme indiqué dans le fichier webapp.ini sur votre hôte.
Votre valeur "target" doit correspondre à l'adresse hôte et au port TCP où vous allez héberger l'application web.
Votre valeur "domain" doit correspondre à vos enregistrements MX définis à l'étape 1.
C'est tout! La plomberie est faite. Vous devriez maintenant être en mesure d'envoyer des certificats à votre adresse d'entrée, ils seront traités et apparaîtront sur votre hôte d'application web – dans ce cas, un fichier nommé bob.lumreeker@gmail.com.crt.
Vous pouvez maintenant envoyer des e-mails chiffrés à Bob, en utilisant les outils décrits dans les parties 2 et 3 de cette série.
Vous pouvez examiner le contenu d'un certificat en utilisant :
openssl x509 -inform PEM -in bob.lumreeker\@gmail.com.crt -text -noout
4. Internes : vérification DKIM, validation des certificats
L'application vérifie que les e-mails reçus ont un DKIM valide et vérifie que les certificats eux-mêmes sont valides, comme décrit ici. Il y a aussi des notes d'implémentation là-dedans, et des idées pour des travaux futurs.
Pour résumer…
Nous avons vu comment les clés publiques des destinataires peuvent être facilement rassemblées en utilisant un e-mail vers une adresse de webhooks de relais entrant. Une fois cela fait, ces destinataires peuvent recevoir leurs messages sous forme chiffrée S/MIME.
C'est tout pour le moment! Envoyez avec bonheur.