在 第 1 部分,我们快速浏览了 S/MIME,查看了在各种邮件客户端中对我们消息流的签名和加密。第 2 部分 带领我们使用简单的命令行工具对电子邮件进行签名和加密,然后通过 SparkPost 发送它们。第 3 部分展示了如何将安全邮件流注入到本地平台,例如 Port25 PowerMTA 和 Momentum。
在这个系列中,我们已经看到如何相对简单地包含 S/MIME 签名。发送 S/MIME 加密邮件则更复杂,因为您需要获得收件人的公钥。使用像 Thunderbird 这样的人类邮件客户端时,这是一回事 - 但应用生成的电子邮件流如何才能做到这一点呢?
但是,请稍等 - 还有另一种方式进入魔多以获取这些密钥。您的服务可以邀请客户(当然是通过电子邮件)向您发送一封签名邮件到已知的客户服务地址。借助 SparkPost 传入中继 Webhook 的神奇力量,我们将为您提取并存储该公钥以供使用。
我们可以简单总结一下这个用例:
作为消息的接收者,我通过电子邮件向您的服务提供我的个人电子邮件签名,以便将来可以以 S/MIME 加密的形式发送电子邮件给我。
从中,我们得出一些更详细的要求:
我们需要一个始终在线、可靠的传入电子邮件服务来接收这些签名电子邮件。
邮件格式没有特殊要求,只要必须携带 S/MIME 签名即可。
因为任何人都可以尝试向该服务发送邮件,因此应该的防御性设计,例如,拒绝坏演员发送的“欺骗”消息。需要有多层检查。
如果一切检查都没问题,该服务将使用著名的纯文本隐私增强邮件(PEM)格式将证书存储在文件中。
还有一些非功能性要求:
机器与机器之间的 Webhook 服务仅从内部发生的响应中很难看到。该服务应提供广泛的人类可读的应用程序级日志。特别是,证书解析和检查应该被记录。
我们为应用程序内部添加测试用例,使用优秀的 Pytest 框架,并在使用与 GitHub 的 Travis CI 集成时,在 check-in 上自动运行这些测试。
好的 - 让我们开始吧!
1. 解决方案概述
这是整体解决方案的外观。
2. 安装、配置和启动 Web 应用
我们将从这一部分开始,这样我们在铺设传入中继 Webhook 之前就可以对其进行全面测试。
Web 应用与第 1 - 3 部分包含在同一 GitHub 项目 中,因此如果您已经跟随了这些部分,您已经拥有它。以下是新内容:
程序 readSMIMEsig.py - 读取电子邮件并解析出中间和用户证书。
程序 webapp.py - 用于 SparkPost 传入中继 Webhook 的简单 Flask 兼容 Web 应用。
webapp.ini - 上述程序的配置文件。配置文件使相同的值能够轻松传递到命令行和 Web 应用程序。
您需要确保您的主机具有正确的 TCP 端口号,以允许来自外部世界的传入请求,这样 SparkPost 就可以将消息 POST 给您的应用。如果您托管在 AWS EC2 上,例如,您需要配置您实例的 安全组。
配置和启动 Web 应用的说明在 这里 - 这相当简单。要检查您的应用是否正在运行并可以从外部世界访问,您可以使用 curl 从其他主机发送(空白)请求,例如:
curl -X POST https://app.trymsys.net:8855/
您应该看到如下响应:
{"message":"请求头中的未知 Content-Type"}
这是一件好事情 - 您的应用正在运行!
在您的主机的 webapp.log 中,您将看到类似于以下内容的输出:
2019-01-15 00:11:07,575,root,INFO,来自 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,| 未知的内容类型:无
为了帮助您立即在应用程序中玩弄真实数据,您可以从项目仓库导入这个特定的 Postman 请求。这模拟了您的 SparkPost 帐户将要做的事情,即它发送一个包含特定有效证书(属于我的测试帐户)的电子邮件的 https POST 到您的应用。
您只需将请求中的目标地址(在灰色框中)更改为与您的安装匹配。如果您在 webapp.ini 中更改了 token 值,请调整 Postman 中的头部值以匹配。
如果您的应用工作正常,您将看到 Postman 中的“200 OK”响应。您的主机 webapp.log 文件将包含如下输出:
2019-01-15 00:11:48,554,root,INFO,来自 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 通过 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 加密签名 2019-01-15 00:11:48,600,root,INFO,| filename=smime.p7s,bytes=3998 2019-01-15 00:11:48,601,root,INFO,| 证书:主题 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,| 证书:主题 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,| 写入文件 ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True
为了快速检查最后一行 - 如果它显示“写入文件”,那么您就可以了。其余部分是展示 DKIM 检查和证书验证过程。
3. SparkPost 传入中继 Webhook 设置
首先,我们选择一个域作为我们的传入消息地址 - 在这里,它将是 inbound.thetucks.com。请按照本指南设置您的域。以下是我详细使用的步骤:
3.1 添加 MX 记录
您需要访问您特定的互联网服务提供商账户。完成后,您可以使用 dig 检查它们 - 这是我域的命令。
dig +short MX inbound.thetucks.com
您应该看到:
10 rx3.sparkpostmail.com. 10 rx1.sparkpostmail.com. 10 rx2.sparkpostmail.com.
3.2 创建传入域
使用 SparkPost Postman API 集合,选择传入域 / 创建.. 调用。POST 请求的主体包含您的域,例如:
{ "domain": "inbound.thetucks.com" }
3.3 创建 Relay Webhook
使用相关的 Postman 调用创建传入中继 Webhook。对于我的情况,消息主体包含:
{ "name": "证书收集 Webhook", "target": "https://app.trymsys.net:8855/", "auth_token": "t0p s3cr3t t0k3n", "match": { "protocol": "SMTP", "domain": "inbound.thetucks.com" } }
如前所述,我建议 设置一个 auth_token 为您自己的秘密值,如在主机上的 webapp.ini 文件中设置的那样。
您的“目标”值需要与您将要托管 Web 应用的主机地址和 TCP 端口匹配。
您的“域”值需要与第 1 步设置的 MX 记录匹配。
就这样!管道已经完成。您现在应该能够向您的传入地址发送证书,它们将被处理并显示在您的 Web 应用程序主机上 - 在这种情况下,一个名为 bob.lumreeker@gmail.com.crt 的文件。
现在您可以使用第 2 和第 3 部分中描述的工具向 Bob 发送加密电子邮件。
您可以使用以下命令检查证书的内容:
openssl x509 -inform PEM -in bob.lumreeker\@gmail.com.crt -text -noout
4. 内部:DKIM 检查、证书验证
应用程序检查接收到的电子邮件是否具有有效的 DKIM,并检查证书本身是否有效,如此处所述。还有实现说明和进一步工作的想法。
总结……
我们已经看到如何通过向传入中继 Webhook 地址发送电子邮件轻松收集收件人的公钥。一旦完成,这些收件人就可以以 S/MIME 加密形式接收他们的消息。
这就是目前的所有内容!祝发送愉快。