纵深防御这个在安全行业被用的很烂的词,乙方的顾问写方案时信手捏来,我想大家的理解可能并不一致。其实我比较赞同lake2用的“河防”以及数字公司用的“塔防”的概念,这些都是比较贴近实际的。下面的篇幅仅从自己的理解来展开,并且主题限定在大规模生产(服务)网络而不是办公网络。
互联网安全的核心
当下各安全公司都偏爱APT和大数据威胁情报之类的概念,在办公网络我想这些是他们圈地运动的战场,不过生产网络似乎仍然遥远。自动化运维的交互模型跟大幅度人机操作的办公网络完全不同,而且现在号称机器学习的方法在实操中表现的很一般,效果不如对攻防模型抽象后定义规则的方式。这里并不是在否定机器学习的方法,只是表达离成熟还尚有距离(我不是在说QVM,请不要对号入座)。
先说一下互联网安全的一些理念性的东西,首先没有漏洞是不可能的,互联网追求快速交付,把安全做的太厚重是“不满足业务需求的”,为追求极致的低缺陷率而大幅增加发布成本是不切实际的,但是互联网安全有几个比较核心的需求:快速检测、有限影响、快速溯源,快速恢复。
通俗解释一遍就是:允许带着一些问题上线,但是有bug或入侵我能快速检测到而不是无知无觉的状态,就算发生了攻击或入侵,我能做到入侵者所获取的权限和造成的影响尽可能的小,并且我有途径或快照还原入侵过程做根因分析,安全事件能在基本不响应不中断业务的情况下恢复到健康状态。当然这个话题也太大,这次只讨论其中关于“有限影响”的部分,在谈及防御之前先看一下攻击路径:
Plan-A:通常路径,从目标系统正面找漏洞,远程直接rootshell在现代基本没有了,大多数是从应用为入口,先获取上层应用的权限,然后通过上传webshell等方式间接获得系统shell,最后提权获得rootshell,后面继续扩大战果的事情就不提了,安全建设的思路自然是要反过来,阻止你扩大战果。
Plan-B:如果正面没有明显可利用的漏洞的话就需要曲折迂回,从周围信任域开始下手,这个信任域是广义上的,包括可arp重定向的,可嗅探的,可会话中间人的,可链路劫持的,相同内网的,口令满足同一规律的,互联互通信任关系的,灾备或镜像站点等,获取一个点后再折返,之后的路径与A类似。
Plan-C:直接针对生产网络不行的话,就需要考虑社会工程学了,针对管理员和办公网络的APT,水坑攻击,针对应用后台管理员的社会工程学技巧,搞定SA自然也就搞定了所有服务器。
纵深防御体系
安全建设是反入侵视角,针对攻击活动中的每一步“埋点”,埋点的寓意在于我假设攻击者到了这一步,我要阻止他进入下一步或者不能带着完全的火力进入下一步还能全身而退。当然这里只针对有限影响,入侵检测之类的部分这里先不展开,后续会有专门的话题。
第一层安全域划分,这个安全域是对业务的抽象,并不是对物理服务器的划分,在大规模分布式架构中,同一个安全域的机器可能并不一定位于同一个物理机房,但是他们对应相同的安全等级,共享一组相同的访问控制策略,只对其他安全域或Internet暴露有限的协议和接口,即使攻击者渗透了其他相邻的服务器,也只能扫描和访问这个安全域内有限的几个端口,没办法自由渗透,这个问题主要解决Plan-B曲线救国时被入侵者“误伤”,以及获得单点root后进一步渗透的扩散,希望能把安全事件爆发的最大范围抑制在一个安全域中,而不是直接扩散到全网。
第二层是基于数据链路层的隔离,只有2层隔离了才能算真正隔离,否则只在3层以上做ACL也是不行的,仍然会被ARP。2层使用VPC,vxlan,vlan等方法相当于在安全域的基础上对一组服务器以更细的粒度再画一道圈,进一步抑制单点沦陷后受害源扩大的问题。在不是特别大的网络中可以直接跳过安全域到这一步。当然安全域的概念在任何时候都是存在的,仅仅是在做划分的事情但不去套这个名词。
二层之上就是协议端口状态过滤,这是绝大多数“防火墙”的场景。解决的还是对黑客暴露的攻击面的问题,即使我的加固做的不到位,不必要的服务没有清理干净,开放了有问题的端口,甚至有些端口上跑着的服务还有漏洞,但是因为被防火墙过滤了,路由不可达,所以攻击者利用不了,他只能在对外或对信任域暴露的端口上去想办法。本质一点就是给攻击者提供“窄带”,有限的访问通道。不过在有复杂嵌套引用关系的大规模生产网络中,出于运维成本的考虑,有时候访问控制策略不会做的很细粒度,因为那样的话如果有台机器挂了换个ip都麻烦。这也是安全的妥协,我之后会有单独篇幅讲做安全是否需要妥协,应该如何妥协,底线是什么。
再往上一层是现在讨论的最多的一层,其实从图中也可以看出你平日的工作都是聚焦于哪层。这一层单独拆开都可以再建一个纵深防御的子体系。应用层通常是暴露在Internet上的攻击面,这一层主要是解决认证鉴权、注入跨站上传之类的应用层漏洞,尽可能把入侵者堵在第一人口之外。如果你在开发WAF,那你对应的也是这一层的工作。
应用层上方是容器、运行时环境。这里的目标是假设我的服务器上的应用程序有漏洞,且攻击者找到了漏洞,我不希望这个漏洞能被成功利用直接跳转到系统权限,而是希望能在这一步阻止他,办法就是通过容器加固,比如阻止一些危险函数的运行,比如上传了webshell但是不被解析执行,比如你想执行eval()并用种种方法变形编码字符窜拼接逃过了应用层的检测,但是到了运行时其实是相同的底层指令,那么无论你在上层多么努力的变形我都会希望在更底层把你揪出来,哪怕不直接阻断我也至少报个警。在绝大多数入侵活动中,上传或生成webshell是从应用权限向系统权限转化的关键一步,所以这一层的防御也是比较重要的。以后如果有时间单独篇幅讲如何对抗webshell。
对抗攻击
如果不幸之前的都没阻止攻击者,对方已经得到了普通用户的shell”$”,那么我肯定不希望你继续得到rootshell,对抗的办法就是大家常见的那些系统加固项,那些文章洋洋洒洒写了一大堆主要就是用在这个场景的,不过最主要的还是对抗本地提权以及内核提权,攻击免疫或称攻击缓解机制例如SMEP、SMAP、DEP、各种ASLR,stack-canay,read-only .PLT .GOT等都是在这里“埋点”,其他的诸如umask=022等也是在这里埋点,似乎看上去这些不太需要安全team的介入,好像都是OS默认的机制?
其实不然,安全做到偏执的程度还是有自己出手的地方,Android出手比标准的Linux更快一点,也许以后就真的没太多需要自己出手的地方了。不过当下各种基于LXC的容器,越来越多的multi tenant的云环境,隔离的机制完全依赖于kernel的健壮性,这些场景下对抗这一层的攻击都显得尤为重要。
如果被拿走了root自然是很令人不爽的事,但还不是最令人不爽的。如果有一天当你的1万台服务器中有500台被人搞了,而且还不能推断是不是装了kernel rootkit的情况下,这种感觉是最要命的,你生了个肿瘤手术摘掉也就算了,那种情况就像你手术完都不确定摘了没,即便500台服务器备份数据重装系统都不彻底,而且近似于你某个子业务要处于离线状态这种极其影响可用性的事情业务部门会把你逼疯掉。
所以不是特别需求要干掉LKM,/dev/kmem,限制/dev/mem的全地址空间读写,另外kernel MAC内核强制访问控制也能限制root只能做有限的事情,尽管理论上内核提权还是能控制一切,不过要在没有开发环境的服务器上实现完整的kernel rootkit功能并保证不在用户态留下蛛丝马迹的概率还是比较低。这样做还有一个好处,把入侵检测聚焦于用户态,不要动不动就去装一堆内核级别的重量级玩意儿,大规模高并发的生产环境伤不起。
在云计算环境中,上面那步可能还不算是单点渗透的终结,更底层还有hypervisor,如果攻击者逃逸出VM那就比较狼狈了,每个厂商都需要考虑一下VMM的保护方案,现在hypervisor这一层很薄不会做的很重,似乎还没有特别成熟和通用的办法,不过肯定会发展起来,会有更多类似于XSM这样的方案。
结语
在一个真正建立纵深防御的系统中,入侵者一般到不了root这一步就会被揪出来,只不过完整的纵深防御要以后的篇幅慢慢写了,这里只是选取了其中一个维度来试图解读这个概念。另一方面,完整的纵深防御体系只有大型互联网公司才可能全覆盖,因为跟安全建设成本有关,所以又涉及另外两个话题:不同规模企业的安全需求和同一公司在不同安全建设阶段的需求,以后再展开。