改造Nginx,让邮件系统也支持双因子验证

起 因

最近在研究双因子认证的时候突然想到:能不能在邮件系统中应用双因子验证呢?作为一个有了想法就想落地的四有好少年,我决定试试。

受制于文化程度和钱包鼓起程度,我在本地用Exchange搭建了一套模拟环境(当然不是正版)。大家不要学习我这种做法,我们要支持正版。嗯嗯。

整个改造分为两块进行,一块是Web端进行双因子验证支持,这块不是难点,通过反向代理服务可以迅速解决。但是,在进行其他协议(例如SMTP、POP3、Exchange)改造的时候,发现事情并没有想象中的这么简单。

技术选型遇到的一点问题

作为一条万年没人权的Web狗,突然间给自己设定了一个这么艰巨的任务,顿时怀疑起了人生。翻了翻自己的技术栈,看来看去也就nginx可能也许大概好像能满足要求,那么久拿他来试试吧。

Nginx是个优秀的反向代理(负载均衡)工具,大多数人都对它在Web方向应用比较熟悉,但其实Nginx还支持对SMTP、IMAP、POP3这些邮件协议进行反向代理或者负载均衡。官网文档见https://www.nginx.com/resources/admin-guide/mail-proxy/。

于是,按照官方文档,写了个配置文件:

然后再用世界上最好的语言PHP,写一个auth_http的配套服务(这个内容下文会提到)。

跑一跑程序,成了,auth_http服务能够正确收到客户端提交的账号密码,可是遇到了两个问题:

1、压根儿没动态验证码出场的机会啊;

2、在SMTP协议的代理中,auth_http只能向nginx返回是否验证通过的结果,nginx无法继续将账号密码向后端节点传递,导致真实的节点无法验证用户身份。

(填写完账号密码后,后端SMTP服务器回应拒绝发送,从Nginx的日志中的确发现我们完成了auth_http的认证)

对于问题1,其实SMTP/POP3/IMAP协议本身并没有提供支持双因子验证的设计,谷歌采用的思路是设置一个随机生成的静态密码与账号绑定。大部分人和谷歌不太一样,我们只能考虑在用户名或密码上动点手脚了:

这样一来,我们在兼容原有协议的基础上可以使邮件系统能够完整地支持双因子验证。至于后一个问题,我翻遍nginx的文档都没有找到着解决方法,上谷歌一搜后,发现很久之前就有同仁们提出过类似疑惑:

http://serverfault.com/questions/726270/setting-up-nginx-to-proxy-adding-ssl-smtp-with-authentication http://mailman.nginx.org/pipermail/nginx/2010-February/019028.html

看来是无解咯?

幸好Nginx是开源的软件,我们还可以靠自己。

阅读源码,发现问题

要怒怼Nginx,首先得深入源码。

Nginx用来处理Mail协议的代码在src/mail/目录下,我们主要关注ngx_mail_proxy_module.c和ngx_mail.h两个文件。

这两个文件大致定义了Nginx对协议的处理过程,其中SMTP协议长这样:

(上图省略了例如环境初始化、容错、其他场景特殊处理等过程)

在原有的Nginx处理过程中,从auth_http得到返回数据后,程序跳过了与后端节点通信的过程,而仅设置了该session对应的后端节点后便不作处理。

所以在官方文档中,auth_http仅能响应Auth-Server、Auth-Port两个头部来指示Nginx的后续操作,不具备向后端转发认证信息的过程。

这时候,我们有两种选择:

1、后端SMTP服务器不再进行登录验证,仅允许来自Nginx的即可;

2、改造Nginx,使得其支持SMTP的认证过程。

第一种方案当然可行,从Nginx的实现来看,甚至可以认为是推荐这么操作的。但是,这个方案有天然的弱点,认证过程需要被解耦。也就是说,认证服务需要同时存在于邮件服务器(IMAP/POP3需要用到)和auth_http中,两者必须一致。

(Nginx源码中,对IMAP已有相关实现)

在我看来这样有点麻烦,在一些特殊的场景下可能会有适配问题,所以我决定改造Nginx,使得它能够支持SMTP协议认证过程的转发。

修改源码,解决问题

修改源码其实非常简单,因为此前的IMAP、POP3中Nginx已经完成了相关的实现,只不过没把它加入SMTP中。考虑到SMTP协议本身不是强认证的(即认证过程是可选的),所以不建议直接强硬地设置这个流程,应当通过配置项管理。

我把修改后的源代码放到了全球最大的同性交友平台上( idapro123/mail_protector),修改的内容并不多,大家不妨可以看看。

这里简要说明修改的内容:

1、在mail配置节中新增了一个可选配置项:smtp_auth_reproxy on | off (default),该配置项的作用是用来控制是否将客户端的AUTH过程传递给后端服务器进行验证;

2、调整了SMTP协议的代理逻辑,当smtp_auth_reproxy被显式置为on的时候,会向后端服务器转发auth_http响应头中的Auth-User和Auth-Pass字段。

(修改后的代码中,同样增加了向后端服务器转发认证请求的过程)

这样一来,我们上面提到的问题都不复存在了,剩下的,就是如何去写一个双因子验证服务。

我同样将auth_http的代码提交到了交友平台上,因为考虑到产线环境需要高性能的读写,才为auth_http服务引入了redis作为中间结果的缓存服务器。另外,在我这边的实际环境中,双因子验证本身即作为一个独立的基础服务提供API调用,所以我在auth_http的实现上也只是简单的引用了这个服务。根据不同的情况,则可能还需要自己进一步修改其中的业务逻辑和具体内容。

顺带的,我们还能通过auth_http完成频控,阻断那些天天开着扫描器在网上拿弱密码库到处碰撞的家伙。

(auth_http中向Nginx返回验证结果和原始密码)

实际测试

编译一下修改的Nginx,这里要注意,编译时至少需要指定以下两个参数,否则,在加载mail模块的时候会报告错误:

–with-mail –with-mail_ssl_module

这里提供一个openresty的编译配置,供大家参考:

编译需要一点时间,完成之后启动Nginx:

/opt/openresty/nginx/sbin/nginx

我们测试一下效果。

(正常情况)

(未验证就想来一发的情况)

(双因子验证失败情况)

(原始密码错误情况)

(触发频控被拒绝的情况)

在实际测试过程中,仍然发现了一些缺陷。

其中最为操蛋的是目前还无法支持Exchange协议,这样一来将导致通讯录和日历功能变得不可用。

参考其他厂的解决方案时,发现他们将日历、通讯录服务独立出来,做成一个在线的iCalendar服务让邮件客户端调用。iCalendar本身可以使用HTTP进行分发(例如使用世界上最好的语言PHP写的DAViCal),所以这个问题其实也能解决。

突然间,我面对着服务器上新增的四个服务(Mail代理、auth_http、Redis、iCal),竟然没有一点欣慰的感觉。为了消灭一个潜在的安全风险,不得不引入多个额外的环节,这么做是不是在和自己最早的愿望背道而驰呢?

原文发布于微信公众号 - FreeBuf(freebuf)

原文发表时间:2017-05-31

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java达人

JWT VS Session

作者:Prosper Otemuyiwa 译者:java达人 来源:https://ponyfoo.com/articles/json-web-tokens-...

4276
来自专栏架构师小秘圈

互联网安全威胁及应对方案

作者:蒋海滔,阿里巴巴国际事业部,高级技术专家,爱好Java/JavaScript,长期关注高性能、并发编程以及Web安全。 来自:高可用架构(ID:ArchN...

3894
来自专栏FreeBuf

如何利用Fluxion诱惑目标用户获取WPA密码

前言 由于ISP替代了易受攻击的路由器,供渗透测试人员选择的诸如Reaver这样的工具越来越少,对于特定的目标,哪些工具有用与否能够确定的也很少。而如果采用暴力...

3166
来自专栏FreeBuf

利用第三方软件0day漏洞加载和执行的木马分析

近期腾讯反病毒实验室捕获了一批针对性攻击的高级木马,该木马使用近期热门的时事话题做诱饵,对特殊人群做持续针对性攻击,目前腾讯电脑管家已经能够准确拦截和查杀该木马...

2238
来自专栏FreeBuf

绕过WiFi验证:四招教你免费使用WiFi

如今越来越多的商场、咖啡店、饭店等公共场所都提供了开放的WiFi网络。不过有时即便我们的设备连上了WiFi,当随便打开一个网页就会立即弹出身份验证页面……是不是...

5567
来自专栏FreeBuf

Web开发者安全速查表

想要开发出一个安全的、健壮的Web应用其实是非常困难的,如果你觉得这实现起来非常简单的话,那么你一定是一个X炸天的程序猿,要么你就是在白日做梦…… 写在前面的话...

2419
来自专栏指尖下的Android

内存和缓存的区别

今天看书的时候又看到了内存和缓存,之所以说又,是因为之前遇到过查过资料,但是现在又忘了(图侵删)。

6922
来自专栏大宽宽的碎碎念

实现一个靠谱的Web认证两种认证JWT怎么存储认证信息防止CSRF总是使用https认证信息不应该永久有效总结一下

48210
来自专栏FreeBuf

一种被动的Tor网络去匿名化方法

目前针对Tor的攻击检测方法都是采用主动攻击,本文将介绍一种被动攻击的去匿名化方法。 ? 一、当前Tor网络检测方法 当前对Tor网络的攻击检测一般有以下几种...

3619
来自专栏腾讯技术工程官方号的专栏

WEB加速,协议先行 ( 下)

本文分享了 STGW 及腾讯云 CLB 在 WEB 协议优化过程中的实践经验,并对WEB协议的未来进行了探讨分析。

6043

扫码关注云+社区

领取腾讯云代金券