1 3

Exchange邮箱安全代理系统开发

概述

邮箱是企业的基础设施,大量的沟通是通过邮件完成的,邮件内容里面承载了非常多的商业敏感信息与机密,员工邮箱账户因社工库、撞库、弱口令、github等途径泄露出去的后果不言而喻。

许多企业的安全工程师可能会从邮箱的账户策略和ACL来保护员工邮箱账户的安全,如强制要求设置强壮的密码、定期修改密码、邮箱服务器仅对内网开放,外网访问需要拨入VPN等。

但这些手段存在以下弊端:

  1. 什么样的口令算安全的,如果正好是被社工库收录的复杂口令,是完全符合密码策略的
  2. 定期修改口令,可能会改回一个已经泄露的复杂的口令
  3. 强壮的口令也可能会通过github、网盘等途径泄露出去
  4. 邮箱放在内网,外网只能通过VPN访问,虽然杜绝了来自外网的攻击,但是员工在外出办公时非常不便

本文要开发的邮件安全代理系统可以兼顾安全性与用户体验。

项目地址:https://github.com/MiSecurity/exchange_proxy

邮箱安全代理架构与功能说明

本次开发的邮件安全代理只适用于Exchange邮件服务器,架构如下:

通过邮件安全代理将内网的邮件服务器集群的443端口发布到外网,Exchange支持OWA、EWS、ActiveSync、RPC协议,是支持通过WEB端、手机端与电脑客户端连接的。 但这样仅是将邮箱服务器的https服务代理出去了,对于账户泄露还是没有任何的防御措施,接下来我们需要给加上二次确认机制。

  • 对于WEB端访问,要求用户除了用户名与密码外,还得输入OTP动态口令
  • 对于手机端,新设备第一次访问时,需要通过短信发送的URL进行设备绑定,只有用户激活过的设备才可以收发邮件,如果收到陌生的设备的激活短信说明账户泄露了
  • 对于电脑端,每次在外网连接时,需要用户通过短信确认自己的出口IP与客户端类型,只有授权后才可以收发邮件

我们线上的承载了2W多人的安全代理是用lua技术栈(openresty + orange框架)开发的,逻辑架构如下所示:

目前的线上的系统做了许多定制化的工作,是通过haproxy、Keepalived和openresty跑起来的,代码量较大,安装、部署与运维相对比较繁琐,光运维文档就可以写一篇文章了,笔者暂时不打算开源这一套系统,本次我们再用go语言实现一套轻量级的。

对EWS协议的支持需要兼容数个不同的邮件客户端,需要踩的坑也比较多,如Mac mail app、windows下的outlook与mac下的outlook都需要定制化兼容,本次为了节省时间,就先不兼容EWS了,有通过电脑收发邮件的需求时可以安装BlueMail与邮箱邮箱大师。这2个PC客户端走的是active sync协议,装在电脑中是可以使用的。

具体实现

我们的安全代理使用了一个https://github.com/vulcand/oxy中间件,我们只要实现了http.Handler就可以开发自己的插件,关于中间件的相关知识可以看看开源图书《Go语言高级编程》的相关章节

接下为分别讲OWA与activeSync协议的插件的开发。

OWA插件的开发

实现一个只有普通owa代理功能的代码如下:

vars.MailConfig.Host是我们在配置文件中配置的域名列表,支持多域名,vars.MailConfig.Backend是后端的邮件服务器地址。

现在只是完成的基本的代理功能,接下来我们添加上OTP动态口令检测的功能:

  • 对于GET请求,修改response的内容,在返回的表单中添加一个输入动态口令的输入框
  • 对于POST请求,先获取到用户名与oto动态口令,先去OTP接口中验证一下otp口令是否合法,合法的话将用户请求传到后端,否则直接在代理层面就阻断请求

详细的代码如下:

util.CheckToken为验证token工具函数,可以在github中查看,我们在main函数中写入以下内容,就实现了一个支持OTP二次验证的WEB端的安全代理了。

listen80Port的目的是监听80端口,将用户请求跳转到443端口,防止用户不会直接输入https,导致404后以为邮件服务器不可用的问题。

效果如下图所示,只有输入正确的账户密码与OTP口令才可以登录。

ActiveSync插件开发

同样一个普通的代理activeSync请求的实现代码如下:

我们需要加上安全过滤功能,封装为一个http.HandlerFunc,详细的功能逻辑如下:

  1. 设备访问时,获取用户名、设备ID、设备类型,指令,如果是第一次访问则新建一条设备信息并保存到redis中,并装设备的状态标识设置为未激活
  2. 用户输入密码的过程中,手机端会通过wbxml协议传递手机端的信息,如设备型号、Imei、当前设备的手机号码、ISP提供商等信息,把这些信息解析出来存入redis
  3. 根据用户名与设备ID,判断当前设备的状态,如果为未激活则进入激活流程,如果已经激活就直接放行,对于已经阻止的设备会直接block
  4. 设备未激活前,也允许用户连接服务器,但会对一些关键的指令做了过滤,保证用户体验的同时也确保了信息安全

在未激活前,过滤的指令列表如下:

代码中有详细的注释,就不细说了,ActiveSync插件的完整代码如下所示:

进入激活流程后需要检测激活的频率,我们定为1分钟只允许激活一次,然后生成激活码和短信并发送给用户。短信的发送频率限定为每10小时一次,防止频繁发送对用户造成骚扰,以下为激活流程相关的代码:

最后在main函数中再加入一条以下的路由,手机端的安全代理功能就生效了:

mux.HandleFunc("/Microsoft-Server-ActiveSync", active_sync.ActiveSyncHandler(active_sync.SyncRedirect))

将手机配置为咱们的代理后,立即会收到一条验证确认短信,如下图所示:

禁止PC端的请求

代理默认会将非路由中的请求透传到后端,目前PC端也是可以访问的,我们需要显式屏蔽一下,防止手机端与WEB端做了安全策略了,却被攻击者通过PC端绕过。

设备激活功能

现在能发出手机端的激活短信了,但还无法激活,为保证用户正常使用,接下来我们需要开发下设备激活的接口,这些接口的路由如下:

  • /static/是提供静态资源的路由,如css、js、图片等
  • /a/是显示激活页面的路由
  • /a/activedevice是设备激活的接口,由前端激活页面的JS调用
  • /a/ignoredevice是设备忽略的接口,也由前端激活页面的JS调用

完整的激活接口代码请查看github,效果如下图所示:

  • 启动代理服务器

  • 激活页面

  • 显示激活状态

后记

该套系统依赖企业的一些基础设备,如OTP系统、HR的通过用户名查找手机的接口、短信接口等。所以不能拿来直接使用,需要根据实际情况对接下相关的接口,然后在配置文件写入正确的配置:

正式上线之前,最好提供相应的管理后台并与内网的管理系统对接,邮件代理管理后台提供以下功能:

  • 管理员可查看、修改每个用户的账户与设备状态
  • 管理员可查看每个设备的激活进程,方便故障排查
  • 用户也可自行管理自己的设备

设备数据保存在redis中,用go/python/php等语言都可以实现,我就不单独提供了。

代理系统的进程可以托管在supervisor或god中,部署了该系统后,可以解决邮件服务器手机端与WEB端的安全,目前的开源版本没有电脑端的安全代理功能,建议在PC端收发邮件时拨入VPN,或者在电脑中用BlueMail客户端收发邮件。

11 27

用go语言给lua写扩展

背景

最近的一个lua项目中需要解析wbxml,WBXML是XML的二进制表示形式,Exchange与手机端之间的通讯采用的就是该协议,我需要解析到手机端提交过来的数据,以提高用户体验。

但是lua没有现成的Wbxml解析库,从头撸一个势必要花费大量造轮子的时间,在网上查找了半天,发现有一个go语言版本的https://github.com/magicmonty/activesync-go,写了几行测试代码,确认该库可以正常解析出Exchange的wbxml数据内容,如下所示:

微服务 VS lua 扩展

最初的方案打算用golang实现一个微服务,供openresty调用,该方案的特点是方便,能快速实现,但缺点也是非常明显的:

  • 性能损耗大:openresty每接收到一个请求都需要调用golang的restful api,然后等待golang把wbxml解析完并返回,这中间有非常大的性能损耗
  • 增加运维成本:golang微服务奔溃后,openresty将无法拿到想到的信息了,在运维时,除了要关注openresty本身外,还要时刻关注golang微服务的业务连续性、性能等指标

最佳的方案是提供一个lua的扩展,无缝集成到openresty中,这样可以完美地规避掉上述2个缺点。

9 21

跨平台的安全检测工具包

概述

xsec-checker是一款服务器安全检测的辅助工具,由GO语言开发,天生支持跨平台,同一份代码可以交叉编译出linux与windows平台下的可执行文件,且无任何库的依赖。

关于跨平台说点题外话,笔者工作前7,8年一直在游戏行业,从安全、运维及开发都有涉猎,记得移动互联网兴起时,许多手机游戏都是先只支持iphone平台,后来才慢慢支持Android平台的,原因是同一款游戏的客户端,需要2个团队,一个team用objective-c开发iphone版的,另一个team用java再重写一版android平台的,到了后期的维护成本及复杂度可想而知。

当时国内最流行的手游开发框架是cocos2d-iphone,是objective-c实现的,后来王哲推出了c++版本的cocos2d-x,只写一套c++版本的代码就可以交叉编译出多种平台的客户端,极大地提高了手机游戏开发的效率。

但业内马上又出现了新的难题,因C++语言难以驾驭,靠谱的C++非常不好招而且人员成本很高,后来cocos2d-x又推出了lua与js的绑定版本,这样的话,在一个研发Team中,只需极少的C++大神就可以搭建好底层框架,具体的业务与逻辑代码,能快速上手lua与js的新手就可以做了,甚至连策划都可以上手,直接写游戏逻辑代码验证自己的设计了,减少沟通与在验证玩法时反反复复让研发修改代码的成本。

目前安全界流行使用python,笔者建议在有高性能要求、跨平台部署、无外部依赖、部署方便、源码加密等要求的场景下使用go语言,go同python一样,也是种全栈的语言。

目前实现的功能如下所示:

项目地址:https://github.com/netxfly/sec_check

8 31

应急响应浅谈

应急响应浅谈

应急响应及应急响应中心

应急响应是安全从业者最常见的工作之一(系统被黑后紧急救火,PDR模型-防护、检测、响应中的三大模块之一)。很多人可能认为应急响应就是发现服务器被黑之后,登录上去查后门的那段过程。 其实应急响应的完整定义为:组织为了应对突发/重大信息安全事件的发生所做的准备,以及在事件发生后所采取的措施

通俗地讲,应急响应不应该只包括救火,还应包括救火前的一系列准备。如果在工作中忽略了准备部分,可能会出现以下几种情况:

  1. 不具备基本的入侵检测能力,平时检测不到入侵事件,更谈不上应急响应了。有可能被入侵成功很久了却浑然不知,攻击者可能早就在达成目标后悄然离去了;
  2. 能检测到入侵事件,但没有专门的应急响应小组,资产管理系统也不完善,安全工程师花了很长时间才找到对应的负责人,因进入响应时间太晚,攻击者可能在达到目标并擦除痕迹后全身而退了,或者进一步把其他关联的系统一并拿下了;
  3. 平时无应急响应技能及入侵检测工具包的积累,接到事件的工程师登录到服务器上绞尽脑汁敲了几行命令后,最后得出『经排查安全的结论』给部门Leader与业务部门了,但真实情况是真被入侵并植入后门了。

现在各大厂商都成立了相应的安全应急响应中心(SRC),用来接收外部白帽子的提交的漏洞与威胁情报,虽然叫应急响应中心,但是这里提交过来的漏洞与情报不需要每次都启动应急响应,需要根据漏洞的类型、危害级别判断。

安全应急响应中心是对自己安全团队所做的安全保障工作的补充,如果SRC发现的漏洞与入侵事件比例很高,安全团队就该好好反思下安全工作为啥只治标不治本、频繁地被动救火了。

指导原则及方法论

应急响应是既紧急又重要的工作,对工程师的技术与意识都有一定的要求,比如很多安全工程师接到业务系统被黑的情报后,可能会联系业务负责人要到服务器账户,然后登录到服务器中检查被渗透的痕迹与后门。这段时间非常宝贵,反映太慢可能会使一些本来可以快速平息的安全小事件发酵成造成重大的损失安全事故。

  • 对于应急响应,首先要了解应急响应的指导原则与方法论,只关注技术的话,可能会本末倒置。

    因信息安全事件的种类和严重程度各有不同,应急响应的处理方式也各不相同,比如DDOS、业务系统被入侵、钓鱼邮件的应急响应方式与过程肯定是不同的,被业内广为接受的应急响应模型与方法论有PDCERF模型与ITIL中的事件管理问题管理模块。

  • 其次要求应急人员有较高的入侵检测能力,否则在排查被入侵的系统时,上去查了半天啥也发现不了,最后给出的结论是安全的。

    笔者在第一份工作时,部门老大要求在进行代码审计与应急响应等依赖人员技术和经验的工作时,必须采用双人Check机制,最后汇总对比结果,防止遗漏。 入侵检测需要检测的项目很多,最好能整理出相应的自动化检测工具自动给出报告,这样不但可以提高工作效率,还可以弱化对应急响应人员技术水平的依赖。

PDCERF模型

Next