3.1 保护并测试Web应用
现代Web服务是由多个层次组成的,这些层次通过HTTP在网络上交互。图3.1展示了一个典型服务的前端、后端和数据层的概要视图。
•前端,使用JavaScript、CSS和HTML编写,这些代码在用户的浏览器上运行,并通过HTTP和后端交互。
•后端Web API,可以使用任何一种开发人员熟悉的语言(Python、JavaScript、Go、Ruby或Java,等等)编写,它响应来自前端的请求,把数据和文档返回给前端。后端通过查询各种各样的来源(比如数据库和外部API)构建出这些数据和文档。
•数据库和Web API组成了第三层,它们对前端是透明的。它们不直接构建文档,而是向后端提供数据,由后端构建返回给用户的文档。
图3.1 现代Web应用在Web浏览器中执行前端代码来查询Web API,Web API使用数据库和其他Web API构建文档。
在第2章中,部署的发票应用由一个Web API和一个数据库组成。本章你将扩展这个应用,为它加上一个简单的前端,来演示保护Web应用所面临的挑战。这个前端如图3.2所示。它只有一个输入框:发票的ID,只展示两个结果:发票的金额和说明。你可以访问GitHub官网的Securing-DevOps主页(链接3.4)来获取改进版本的发票应用源代码。注意,代码中包括了这一章中剩余的全部修改。使用git diff这样的比较工具来查看代码的变化。
图3.2 发票应用的Web前端是一个简单的HTML表单,显示了发票的金额。
乍一看,很难发现在这样简单的页面中存在着哪些潜在的问题。但是,不能因为它很简单就忽视了它的安全性:这个页面存在着跨站脚本、跨站请求伪造、点击劫持和数据泄露等风险,它容易受到攻击。这些问题我稍后会在本章中加以解释,现在我们先来讨论如何发现这些问题。
人工查找漏洞是一项耗时且乏味的工作。我们将使用OWASP ZAP来大幅度降低这项工作的难度,它是一个专为扫描Web应用漏洞而设计的开源工具。ZAP是一个Java应用,你可以从链接3.5中下载。它还提供了一个Docker容器,可以通过docker pull owasp/zap2docker-weekly这条命令获取。
从传统意义上来说,安全团队负责操作漏洞扫描器,要么在团队执行应用审计时手动扫描,要么在每周或每月定期扫描。这就要求安全团队先要对扫描器的报告进行分析,之后再和负责修复问题的开发团队沟通。人工审核需要时间,而且由于扫描只是定期执行,所以在问题被发现之前,易受攻击的服务可能已经在生产环境中部署了一段时间。
我们可以通过DevOps方法来改进工作流。你可能想起了第1章中的图1.5,它描绘了测试驱动安全(TDS)。将漏洞扫描集成到流水线上就是实现TDS的第一步,重点关注图3.3所示的CI流水线。这个思路很简单:每次代码在被签入代码仓库中的特性分支时,你就可以运行扫描,而不是定时运行扫描。在CI中运行漏洞扫描器,让安全测试向通常由CI工具运行的单元测试和集成测试靠近。这样将有助于消除只有安全团队才能运行并理解安全测试的特殊状态,可以让安全测试更贴近负责修复这些问题的团队。你的目标就是当代码还在流水线中的时候,开发者就可以捕获安全问题,而不是等到代码运行在生产环境中时才去发现它们。
图3.3 根据第1章中的TDS模型,针对应用的安全测试应该作为CI流水线的一部分来直接运行。
快速扫描
扫描一个Web应用以寻找其中的漏洞需要花费几小时,而且并不适合开发者需要快速迭代代码更改的工作流。我们需要快速扫描。ZAP为此可以限制扫描的范围和深度,让扫描在一分钟之内完成。我们将这种类型的漏洞评估称为基线扫描,它只关注基本的控制,而不是全面的漏洞评估。要了解更多关于ZAP基线扫描的信息,请参考链接3.6。
在CircleCI中集成ZAP Docker容器来运行针对发票应用的基线扫描。操作流程如图3.4所示:
图3.4 代码仓库通知CI平台(1)需要测试特性分支上的补丁,这会触发应用容器的构建(2),ZAP会针对这个容器来运行(3)。扫描的结果决定了测试应该是通过还是失败(4)。
1.代码仓库通知CI平台,有拉取请求被提交。
2.CI平台获取一份变更代码的拷贝,运行应用测试并构建应用容器。
3.CI平台获取ZAP容器的拷贝,并针对应用容器来运行。
4.扫描的结果决定了CI平台是通过还是拒绝这次变更。
内部TDS
这里我们再次使用CircleCI作为示例,但类似的工作流可以在任何CI环境中实现,包括在自己的数据中心里运行的流水线。例如,我们在实现Mozilla的ZAP基线扫描时,将其作为一条Jenkins部署流水线的一部分来运行,它运行在一个私有的CI平台中,对那些部署到预生产环境中的应用进行扫描。
你可以用很多种方法将TDS集成到流水线之中。我们只是简单地利用第三方平台作为本书的示例,但你可以在组织内部运行完整的流水线来达到同样的效果。
请关注概念,而不是实现细节。
你要修改CircleCI的配置来获取ZAP容器,并针对发票应用来执行它,才能实现这个工作流。发票应用将在自己的Docker容器中运行,并暴露出供ZAP扫描的本地IP和端口。这些修改体现在config.yml文件中,如代码清单3.1所示。
对CircleCI的变更以补丁形式作为一次拉取请求来进行提交,这将触发CircleCI运行此配置。图3.4中描绘的四个步骤将会依次执行。如果ZAP发现了一个漏洞,它会以一个非0的状态码退出,告诉CircleCI构建失败了。如果你对第2章中的没有任何规避措施的发票应用源代码执行这些测试,扫描会返回四个安全故障,如代码清单3.2所示。
现在你可能觉得扫描的输出没有什么意义,但它却告诉了我们一件事:发票应用不安全。在下一节里,我将说明这些问题及如何规避它们,还会再次用到基线扫描来验证我们是否修复了这些问题。