Total Pageviews

Thursday, 17 September 2015

Email与TLS加密传输

提起Email与TLS加密传输,很多手动设置过Email客户端的人会说:我知道这个,我在用的qq邮箱/hotmail/yahoo.cn邮箱支持TLS加密传输。
曾经我也以为邮件的加密传输就是这么简单。但是昨天发现的一个事实让我知道,GFW不会让大家这么省心。

诡异的connection reset

事情的起因是:我想参与金山WPS for Linux版的测试,用我的Gmail邮箱向帖子中提到的邮箱地址wps_linux@kingsoft.com发送了报名邮件发送了报名邮件。
接下来的几天我的邮箱收到了多次Gmail发出的Delivery Status Notification:
This is an automatically generated Delivery Status Notification

THIS IS A WARNING MESSAGE ONLY.

YOU DO NOT NEED TO RESEND YOUR MESSAGE.

Delivery to the following recipient has been delayed:

    XXXXXXX@kingsoft.com

    Message will be retried for 2 more day(s)

    Technical details of temporary failure:
    Unspecified Error (SENT_RCPT): Connection reset by peer
这里的Connection reset by peer,对于所有了解过GFW的人都不陌生。在这之前陆续也有我的邮件收到类似的Delivery Status Notification。当时以为只是部分Google的IP地址被墙导致的超时。在看到这里的Connection reset之后终于忍不住我开始排查原因了。感谢@yangzhe1990的帮助,在回忆了一下SMTP协议的命令之后我得到了排查的结论:

邮件地址被「墙」

这个结论真是无比神奇。到底如何被墙呢?举实际的例子说明:
# 从墙外向墙内SMTP服务器发起telnet连接
$ telnet mail.kingsoft.com 25
Trying 219.141.176.248...
Connected to telecom.mail.kingsoft.com.
Escape character is '^]'.
220 mail.kingsoft.com ESMTP
EHLO yegle.net
250-mail.kingsoft.com
250-8BITMIME
250 SIZE 20971520
MAIL FROM:我的邮箱地址@gmail.com
Connection closed by foreign host.

# 从墙内向墙外SMTP服务器发起telnet连接
$ telnet aspmx.l.google.com 25
Trying 209.85.225.27...
Connected to aspmx.l.google.com.
Escape character is '^]'.
220 mx.google.com ESMTP u6si11379881igw.58
EHLO yegle.net
250-mx.google.com at your service, [183.151.34.162]
250-SIZE 35882577
250-8BITMIME
250-STARTTLS
250 ENHANCEDSTATUSCODES
MAIL FROM:<mail@example.com>
250 2.1.0 OK u6si11379881igw.58
RCPT TO:<我的邮箱地址@gmail.com>
551 User not local; please try <forward-path>
Connection closed by foreign host.
也就是说,我无法从墙外向墙内SMTP服务器发邮件,墙内也无法向我的邮件地址发邮件(需要连接google的MTA服务器)
发现这点之后我连声感慨:这待遇真是高档,没话说。我终于明白为什么支付宝的通知邮件很久一段时间都没有成功收到了。

发送邮件时都发生了什么

对于邮件收发的过程,之前还真没仔细了解过。遇到这种事情才去看了一下资料。整理了一下一封电子邮件的收发大致流程,这里以tom@example.comjerry@example.net发送邮件为例。
几个词汇:
  • SMTP服务器:用于用户->服务器发送邮件时,接收来自用户的邮件。假设example.com的SMTP服务器地址为smtp.example.com
  • MTA服务器:用于服务器->服务器发送邮件时,接收外部服务器投递到本坞的邮件。MTA服务器本身其实也是一个SMTP服务器。假设example.net的MTA服务器地址为mx.example.net
发送邮件的大致流程:
  1. Tom在自己的邮件客户端里写好邮件
  2. Tom的邮件客户端连接到smtp.example.com的25端口,将邮件内容发送到example.com的服务器上保存
  3. example.com根据这封邮件的目的地址,判断本邮件需要传送给外部服务器example.net
  4. example.com进行DNS查询,查询example.net的MX记录对应的MTA服务器是mx.example.net
  5. example.com作为一个SMTP客户端,连接到mx.example.net的25端口,发送邮件给example.net
  6. example.net判断邮件收件地址是本地地址,接收邮件并投递到相应用户
UPDATE: 感谢@xmxsuperstar的提醒。一个域邮件到另外一个域的传递,中间有可能经过不止一个MTA做中转。

发信过程中如何进行传输加密?

「加密」很时髦,各种免费邮箱都提供了TLS加密传输功能,有的还支持旧的SSL加密功能,让人很有「安全感」。但事实上怎样呢?
前面有提到「SMTP服务器」和「MTA服服务器」。而绝大多数免费邮箱提供的TLS加密传输、SSL加密只是在SMTP服务器上进行了部署设置。在MTA服务器上不支持TLS、SSL加密。
也就是说,在上面说的流程里,绝大多数免费邮箱在步骤2里(邮件客户端到邮箱SMTP服务器阶段)实现了TLS加密传输,而根本没有在步骤5里(邮件服务器到外坞邮件MTA服务器阶段)进行加密。这个服务端到服务端之间的通讯过程,用户是没有任何办法进行介入的。
更关键的是:即使你作为邮件服务提供商,让自己的MTA服务器支持了TLS加密传输,你仍然需要依赖外部邮件服务器在向你的MTA服务器发送邮件时,选择使用TLS加密传输。这样苛刻的条件让绝大多数邮件服务器之间的通讯都是明文、不加密的(至少,邮件收发地址是明文,不可能完成加密的)
我说的「绝大多数免费邮箱」,存在例外。以下是目前发现的,在收(自己的MTA服务器)、发(往外部MTA服务器发送邮件)两个方向都使用TLS加密传输的邮件服务提供商:
  • Gmail
  • iCloud
  • FastMail.fm
而国内常见的邮件服务都是不支持TLS加密传输的。已测试确认不支持TLS的有:
  • qq.com
  • hotmail.com
  • live.com
  • 163.com

我使用了GPG加密,有没有TLS加密传输无所谓吧?

这个观点是错误的。你的邮件内容加密了,GFW可以用简单粗暴的方式直接过滤掉你的邮件。
  • TLS加密传输是传输时加密,在两个邮件服务器通讯期间数据是加密状态,但是在这个阶段前后,邮件仍然是明文可读的。理论上说邮件服务提供商的工程师可以看见你的明文邮件内容
  • GPG加密是端到端加密,理论上说除了邮件收发双方,其他任何人都无法获取邮件明文。但是GPG不对收发地址进行加密

如何测试我使用的邮件服务器是否支持TLS加密传输?

证实自己的邮件服务器在收信方向上是否支持TLS加密传输比较简单。以下假设我需要知道qq.com邮箱是否支持收信时TLS加密传输
确认你的邮件服务提供商的MTA服务器地址。Windows用户请使用nslookup -type=MX qq.com, 感谢@ayanamist的提醒
$ dig MX qq.com

; <<> DiG 9.7.3-P3 <<> MX qq.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38689
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 4, ADDITIONAL: 0

;; QUESTION SECTION:
;qq.com.                IN  MX

;; ANSWER SECTION:
qq.com.         2178    IN  MX  30 mx1.qq.com.
qq.com.         2178    IN  MX  10 mx3.qq.com.
qq.com.         2178    IN  MX  20 mx2.qq.com.

;; AUTHORITY SECTION:
qq.com.         62766   IN  NS  ns1.qq.com.
qq.com.         62766   IN  NS  ns2.qq.com.
qq.com.         62766   IN  NS  ns3.qq.com.
qq.com.         62766   IN  NS  ns4.qq.com.

;; Query time: 360 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Tue May  1 00:07:56 2012
;; MSG SIZE  rcvd: 156>>
使用telnet命令连接到MTA服务器的25端口
$ telnet mx1.qq.com 25
Trying 64.71.138.83...
Connected to mx1.qq.com.
Escape character is '^]'.
220 newmx33.qq.com MX QQ Mail Server
EHLO example.com
250 newmx33.qq.com
STARTTLS
502 Error: command not implemented # 此处会有相关的错误信息,表示此MTA服务器不支持TLS加密传输
证实自己的邮件服务器在发信方向上是否支持TLS加密传输,暂时没有找到简单的方法。在网上找了一个测试TLS的网站可以进行测试:http://checktls.com/perl/TestSender.pl

我该如何选择?

  1. 国内的邮箱用户:请只与国内邮箱用户收发邮件。与国外邮箱用户收发邮件100%会经过GFW的审核(或者说检查)。(说实话我真高兴我的邮箱再也收不到国内邮箱用户的邮件了!
  2. 国外不支持TLS加密传输的邮箱用户:尽量转用支持TLS加密传输的邮箱如Gmail。如果无法做到,请尽量使用GPG加密传输你发出的邮件,并请提醒收信方,他回复的邮件将以明文在公网上传输
  3. 国外支持TLS加密传输的邮箱用户:好样的!但是请提醒所有没有使用支持TLS加密传输邮箱的收件人,你向他发送的邮件以及他回复的邮件将以明文在公网上传输,并请建议他使用支持TLS加密传输的邮箱服务.
from http://blog.yegle.net/2012/05/01/email-and-tls/