欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

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

来源:本站整理 作者:idapro 时间:2017-05-31 TAG: 我要投稿

一、起因
最近在研究双因子认证的时候突然想到:能不能在邮件系统中应用双因子验证呢?作为一个有了想法就想落地的四有好少年,我决定试试。
受制于文化程度和钱包鼓起程度,我在本地用Exchange搭建了一套模拟环境(当然不是正版)。大家不要学习我这种做法,我们要支持正版。嗯嗯。
整个改造分为两块进行,一块是Web端进行双因子验证支持,这块不是难点,通过反向代理服务可以迅速解决。但是,在进行其他协议(例如SMTP、POP3、Exchange)改造的时候,发现事情并没有想象中的这么简单。
二、技术选型遇到的一点问题
作为一条万年没人权的Web狗,突然间给自己设定了一个这么艰巨的任务,顿时怀疑起了人生。翻了翻自己的技术栈,看来看去也就nginx可能也许大概好像能满足要求,那么久拿他来试试吧。
Nginx是个优秀的反向代理(负载均衡)工具,大多数人都对它在Web方向应用比较熟悉,但其实Nginx还支持对SMTP、IMAP、POP3这些邮件协议进行反向代理或者负载均衡。官网文档见https://www.nginx.com/resources/admin-guide/mail-proxy/。
于是,按照官方文档,写了个配置文件:
mail {
    server_name mail.example.com;
    auth_http   localhost:9000/auth_http;
    server {
        listen    25;
        protocol  smtp;
        smtp_auth login plain;
    }
    server {
        listen    110;
        protocol  pop3;
        pop3_auth plain;
    }
    server {
        listen   143;
        protocol imap;
    }
}
然后再用世界上最好的语言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协议本身不是强认证的(即认证过程是可选的),所以不建议直接强硬地设置这个流程,应当通过配置项管理。

[1] [2]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载