Reach

Grow

Manage

Automate

Reach

Grow

Manage

Automate

S/MIME 第 4 部分:通过 SparkPost 入站中继 Webhook 轻松收集收件人公钥

电子邮件

1 min read

S/MIME 第 4 部分:通过 SparkPost 入站中继 Webhook 轻松收集收件人公钥

电子邮件

1 min read

S/MIME 第 4 部分:通过 SparkPost 入站中继 Webhook 轻松收集收件人公钥

在这个系列中,我们已经看到,包含 S/MIME 签名是相当直接的。发送 S/MIME 加密邮件则更复杂,因为您需要获取收件人的公钥。当您使用像 Thunderbird 这样的电子邮件客户端时,这是一回事,但应用程序生成的电子邮件流又如何运作呢?

第一部分中,我们快速浏览了S/MIME,了解了跨多个邮件客户端对消息流进行签名和加密的过程。第二部分通过一个简单的命令行工具来签名和加密邮件,然后通过SparkPost发送它们。第三部分展示了如何将安全邮件流注入到如Port25 PowerMTAMomentum这样的本地平台中。

在这系列中,我们看到包含S/MIME签名是相当直接的。发送S/MIME加密邮件则更为复杂,因为您需要获取接收者的公钥。这在您使用如Thunderbird这样的邮件客户端时是一个事情 —— 但这如何在应用生成的邮件流中运作呢?

但等等 —— 有另一种进入Mordor的方法来获取那些密钥。您的服务可以邀请您的客户(当然通过邮件)发送一个签署的邮件到一个已知的客户服务地址。使用SparkPost Inbound Relay webhooks的神奇力量,我们将提取并存储那个公钥供您使用。

我们可以通过一个简单的用例总结这一点:

  • 作为消息的接收者,我通过邮件向你的服务提供我的个人邮件签名,以便未来的邮件可以以S/MIME加密方式发送给我。

从这一点,我们推导出一些更详细的需求:

  • 我们需要一个始终在线、可靠的入站邮件服务来接收这些签署的邮件。

  • 邮件格式应无需任何特殊要求,只需携带S/MIME签名即可。

  • 由于任何人都可以尝试向该服务发送邮件,服务设计应具有防御性,例如,拒绝来自不良行为者的“伪造”消息。需要进行多层次的检查。

  • 如果一切检查正常,服务将使用众所周知的纯文本Privacy-Enhanced Mail (PEM)格式将证书存储在一个文件中。

还有一些非功能需求:

  • 机器对机器的webhook服务可能仅通过响应看不到内部发生的情况。服务应提供广泛的人类可读的应用级日志。尤其是,证书解析和检查应被记录。

  • 我们为应用内部添加测试用例,使用Pytest框架,并通过Travis CI与GitHub集成自动运行这些测试。

好了——让我们开始吧!

1. 解决方案概览

这是整体解决方案的样子。

Diagram depicting a secure email flow illustrating how emails are verified using certificates for secure transmission.

2. 安装、配置和启动 web app

我们会从这一部分开始,因此在处理入站中继webhooks之前,我们将其充分测试。

网络应用程序包含在同一个GitHub项目中,与第1至3部分相同,因此如果您已经按照那些部分操作过了,那么您已经拥有它。这里是新的部分:

  • 程序 readSMIMEsig.py – 读取电子邮件并解析中间和用户证书。

  • 程序 webapp.py – 用于 SparkPost 入站中继 Webhooks 的简单 Flask 兼容网络应用程序。

  • webapp.ini – 上述的配置文件。配置文件使得相同的值可轻松传递到命令行和网络应用程序中。

您需要确保您的主机拥有正确的TCP端口号对外部世界的入站请求开放,以便SparkPost可以将消息POST到您的应用程序。如果您托管在AWS EC2上,例如,您将需要配置实例的安全组

配置和启动web应用程序的说明给出在这里 – 这非常简单。为了检查您的应用程序是否正运行且可以从外部世界访问,您可以使用 curl 从另一个主机发送(空白)请求,例如:

curl -X POST https://app.trymsys.net:8855/

您应该看到这样的响应:

{"message":"请求头中未知的内容类型"}

这是件好事——您的应用程序正在运行!

在您主机的 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,| 未知内容类型:None

为了帮助您立即在应用程序中使用真实数据,您可以从项目仓库导入此特定Postman请求。这模拟了您的SparkPost账户的操作,即发送包含指定的、有效的证书(属于我一个测试账户)的https POST到您的应用程序。

您只需在请求中(上面的灰色框内)更改目标地址以匹配您的安装。如果您更改了 webapp.ini 中的令牌值,请调整 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 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,| 写入文件 ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True

为了快速核对,请查看最后一行 - 如果它显示“写入文件”,那么您已成功。其余部分显示的是 DKIM 检查和证书验证过程。

我们会从这一部分开始,因此在处理入站中继webhooks之前,我们将其充分测试。

网络应用程序包含在同一个GitHub项目中,与第1至3部分相同,因此如果您已经按照那些部分操作过了,那么您已经拥有它。这里是新的部分:

  • 程序 readSMIMEsig.py – 读取电子邮件并解析中间和用户证书。

  • 程序 webapp.py – 用于 SparkPost 入站中继 Webhooks 的简单 Flask 兼容网络应用程序。

  • webapp.ini – 上述的配置文件。配置文件使得相同的值可轻松传递到命令行和网络应用程序中。

您需要确保您的主机拥有正确的TCP端口号对外部世界的入站请求开放,以便SparkPost可以将消息POST到您的应用程序。如果您托管在AWS EC2上,例如,您将需要配置实例的安全组

配置和启动web应用程序的说明给出在这里 – 这非常简单。为了检查您的应用程序是否正运行且可以从外部世界访问,您可以使用 curl 从另一个主机发送(空白)请求,例如:

curl -X POST https://app.trymsys.net:8855/

您应该看到这样的响应:

{"message":"请求头中未知的内容类型"}

这是件好事——您的应用程序正在运行!

在您主机的 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,| 未知内容类型:None

为了帮助您立即在应用程序中使用真实数据,您可以从项目仓库导入此特定Postman请求。这模拟了您的SparkPost账户的操作,即发送包含指定的、有效的证书(属于我一个测试账户)的https POST到您的应用程序。

您只需在请求中(上面的灰色框内)更改目标地址以匹配您的安装。如果您更改了 webapp.ini 中的令牌值,请调整 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 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,| 写入文件 ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True

为了快速核对,请查看最后一行 - 如果它显示“写入文件”,那么您已成功。其余部分显示的是 DKIM 检查和证书验证过程。

我们会从这一部分开始,因此在处理入站中继webhooks之前,我们将其充分测试。

网络应用程序包含在同一个GitHub项目中,与第1至3部分相同,因此如果您已经按照那些部分操作过了,那么您已经拥有它。这里是新的部分:

  • 程序 readSMIMEsig.py – 读取电子邮件并解析中间和用户证书。

  • 程序 webapp.py – 用于 SparkPost 入站中继 Webhooks 的简单 Flask 兼容网络应用程序。

  • webapp.ini – 上述的配置文件。配置文件使得相同的值可轻松传递到命令行和网络应用程序中。

您需要确保您的主机拥有正确的TCP端口号对外部世界的入站请求开放,以便SparkPost可以将消息POST到您的应用程序。如果您托管在AWS EC2上,例如,您将需要配置实例的安全组

配置和启动web应用程序的说明给出在这里 – 这非常简单。为了检查您的应用程序是否正运行且可以从外部世界访问,您可以使用 curl 从另一个主机发送(空白)请求,例如:

curl -X POST https://app.trymsys.net:8855/

您应该看到这样的响应:

{"message":"请求头中未知的内容类型"}

这是件好事——您的应用程序正在运行!

在您主机的 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,| 未知内容类型:None

为了帮助您立即在应用程序中使用真实数据,您可以从项目仓库导入此特定Postman请求。这模拟了您的SparkPost账户的操作,即发送包含指定的、有效的证书(属于我一个测试账户)的https POST到您的应用程序。

您只需在请求中(上面的灰色框内)更改目标地址以匹配您的安装。如果您更改了 webapp.ini 中的令牌值,请调整 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 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,| 写入文件 ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True

为了快速核对,请查看最后一行 - 如果它显示“写入文件”,那么您已成功。其余部分显示的是 DKIM 检查和证书验证过程。

3. SparkPost inbound relay webhooks 设置

首先,我们选择一个域名作为我们的入站消息地址——在这里,它将是 inbound.thetucks.com。按照此指南设置您的域名。我使用的详细步骤如下:

3.1 添加 MX 记录

您需要访问您的特定 Internet 服务提供商帐户。完成后,您可以使用 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" }

Postman desktop application with an open tab displaying a 'Create an Inbound Domain' API request, featuring fields such as domain input, several header options, and a JSON payload, aimed at testing and automating API workflows.


3.3 创建中继 Webhook

使用相关的 Postman 调用创建一个入站中继 webhook。就我而言,消息主体包含:

{ "name": "Certificate Collection Webhook", "target": "https://app.trymsys.net:8855/", "auth_token": "t0p s3cr3t t0k3n", "match": { "protocol": "SMTP", "domain": "inbound.thetucks.com" } }

如前所述,我建议设置一个 auth_token为您自己的秘密值,如您主机上的 webapp.ini 文件中设置。

您的“target”值需要与您托管 Web 应用程序的主机地址和 TCP 端口匹配。

您的“domain”值需要与步骤 1 中设置的 MX 记录匹配。

Postman interface, showing the process of creating a relay webhook with detailed JSON configuration, with sections including request method, parameters, and code snippet.


就是这样!管道连接完成。您现在应该可以将证书发送到您的入站地址,它们将被处理并显示在您的 Web 应用程序主机上——在这种情况下,文件名为 bob.lumreeker@gmail.com.crt。

现在,您可以使用本系列第 2 和第 3 部分中描述的工具向 Bob 发送加密电子邮件。

您可以使用以下方式检查证书内容:

openssl x509 -inform PEM -in bob.lumreeker\@gmail.com.crt -text -noout

4. Internals: DKIM 检查, 证书验证

该应用程序检查接收到的电子邮件是否具有有效的DKIM,并检查证书本身的有效性,如此处所述。 其中还有实现说明和进一步工作的想法。

总结…

我们已经看到如何使用电子邮件轻松收集收件人的公钥,这是通过转入中继webhooks地址完成的。完成后,这些收件人可以接收S/MIME加密形式的消息。

就到这里!发送愉快。

让我们为您联系Bird专家。
在30分钟内见证Bird的全部威力。

通过提交,您同意 Bird 可能会就我们的产品和服务与您联系。

您可以随时取消订阅。查看Bird的隐私声明以获取有关数据处理的详细信息。

Newsletter

通过每周更新到您的收件箱,随时了解 Bird 的最新动态。

让我们为您联系Bird专家。
在30分钟内见证Bird的全部威力。

通过提交,您同意 Bird 可能会就我们的产品和服务与您联系。

您可以随时取消订阅。查看Bird的隐私声明以获取有关数据处理的详细信息。

Newsletter

通过每周更新到您的收件箱,随时了解 Bird 的最新动态。

让我们为您联系Bird专家。
在30分钟内见证Bird的全部威力。

通过提交,您同意 Bird 可能会就我们的产品和服务与您联系。

您可以随时取消订阅。查看Bird的隐私声明以获取有关数据处理的详细信息。

R

Reach

G

Grow

M

Manage

A

Automate

Newsletter

通过每周更新到您的收件箱,随时了解 Bird 的最新动态。