威胁途径与软件安全:保护环境安全
在这个软件安全系列的第2部分中,我们探讨了DevOps是如何在软件安全防护上发挥关键作用的。虽然安装会费一些时间,但自动化的过程提供的投入产出比是非常可观的。将员工的双手从重复性的劳动中解放出来,您就可以获得一致、安全、可靠的结果。现在我们来了解一下什么样的手段能够保证您的应用程序在安全的环境中运行。
一言以蔽之,环境就是您运行软件应用的地方。您可能将主机软件放在办公室里,或者更可能的是放在云端。不论是哪一种情况,配置底层设备和网络时都要将安全铭记于心,这一点很重要。
在本文中,我们会从宏观的角度出发,逐渐深入探讨各个细节。首先是整体网络和分离环境的办法,然后了解在VM层面应该做些什么。这个系列中有一个反复提及的主体,那就是安全在整个过程中的重要性。哪怕是一个错误也可能让您的努力付诸东流。
防火墙与安全策略
网络安全的第一道防线是防火墙,它可以让您控制和监控出入您的网络的数据。防火墙常常伴随着一套安全策略,这些安全策略可以很简单,例如只让HTTP/HTTPS端口的流量进入您的网络,这么做可以防止他人通过其他端口访问网络,他们的请求也会被拒绝。简单的策略也可以扩展到更多用途中,例如拒绝不含UserAgent字符串的请求——这是机器人尝试访问网络时的常见签名。另一方面,配置不当的防火墙可导致数据被窃,美国第一资本金融公司就在这方面付出了血的教训。
复杂的防火墙可以检测恶意攻击(比如单一来源的多次请求),并在它们抵达您的内部网络以前将其拒之门外。复杂的防火墙甚至还能利用AI技术监控流量模式,并根据这些数据对规则进行动态更新。例如,大流量请求的源位置发生显著变化可能是一次攻击的信号,于是您就可以采取主动措施躲过这次攻击。
维持网络的安全性与封闭性
您的应用程序是在网络中运行的,并且您需要确定这个应用具体在网络中的哪一个位置运行。那么能不能是可公开访问的位置?为什么?若您的应用无需触及互联网,又为何要给予其互联网的访问权限?例如,您的数据库所在的设备应该基本断绝一切公开访问。这台设备应该放在专用的子网络中,需要访问这台设备的应用服务器应该拥有该子网络的访问权限。
出于同样的理由,应用程序应该只能在“需要”时与其他应用通信。通过减少网络中暴露点的数量,当某个部分发生安全问题时,您就可以把您的环境部分隔离出来。换句话说,攻击者侵入网络的途径会极其有限。
隔离生产环境和测试环境
生产环境与测试环境之间绝对、绝对、绝对不能相互访问,这一点是毫无疑问的。生产环境应该尽可能保证封闭性。将测试环境指向生产数据从来都不是什么好主意,即使这样做可以降低调试难度。如果需要在下层环境中访问生产数据,您一定要使用生产数据的拷贝,将其消毒(去除敏感内容)后再放到测试环境中。
测试环境就是这样。它充斥着未经验证的代码和数据,这些代码和数据全都还未通过您设置的安全审核机制。若将这样的环境和生产环境混合在一起,就会形成额外的风险和暴露。实际上,若您是在AWS云上运行,那么为这些环境创建完全独立的账户是很好的做法。这样虽然会增加管理上的复杂度,但却能够帮助理解如何避免交叉影响。
最低权限访问
访问各个环境,特别是生产环境时,应该严格遵守按需访问原则。不了解(或无需了解)应用程序如何在服务器上运行的前端开发人员不应该拥有服务器的访问权限。这一方针同样适用于安装和运行环境的其他开发人员或操作人员——除非需要,否则不应该拥有访问权限。即便拥有访问权限,访问权限也应该拥有明确的有效期,方便相关人员完成特定任务,并在此之后予以撤销。市面上有一些工具可以帮助实现这一目的。例如,若在AWS中,您可以使用STS创建临时的认证信息,该认证信息会在经过指定的时间后过期,这样您就无需时刻记着在任务结束后撤销认证信息。STS还提供一系列的检查和平衡功能,任何人在未取得另一人的签名以前都无法独自执行带有风险的操作。
轮换密钥
密钥应该处于不断轮换的状态。若访问密钥不断换入、换出时,那么当其中一把密钥泄露时,影响也不会持续很长时间。甚至对于不暴露在互联网中的内部应用,您也应该让这些应用的通信密钥保持轮换。不断变换的密钥最难破解的密钥。如果人们不生成密钥,那就不会泄露密钥。
定期更新操作系统/软件
您的软件运行在哪一个版本的操作系统(OS)上?这个版本最近有推出安全补丁吗?这个操作系统是否已经到了产品生命的末期?这些都是您要定期问自己的问题。操作系统每天都会有新的漏洞被挖掘出来,因此生产商会发行安全补丁来消除这些漏洞。根据通用漏洞披露的调查结果,过去5年中,漏洞的数量始终在稳步增长。如果不给操作系统打补丁,您就会让自己暴露在远程执行、权限升级、信息披露等攻击中。
这也同样适用于您开发应用时使用的语言和框架。Java 11发行后,您还在运行Java 8吗?为什么?您应该时刻关注应用中的每一种框架是否推出了安全更新,并定期安装这些更新。
展望
那么,现在我们已经保证了应用程序的周边安全。您的业务流程已经就绪,代码和部署流水线实现了自动化,环境的安全也得到了保障。还剩下一件事要做——那就是保护应用程序本身的安全。在这个系列的最后一个部分中,我们会探讨各种输入和输出,让您的应用坚不可摧。