在CI中实现持续Web安全扫描
本文首发表于InfoQ:http://www.infoq.com/cn/articles/WebScan-CI
一. 当前Web应用安全现状
随着中国互联网金融的爆发和繁荣,Web应用在其中扮演的地位也越来越重要,比如Web支付系统、Web P2P系统、Web货币系统等。对于这些金融系统来讲,安全的重要性是不言而喻的, 一旦黑客利用安全漏洞入侵系统后,损失的不仅仅是数据,还包括企业或者客户的财产。
国内著名的乌云漏洞平台,每天都会爆出十几条甚至几十条各大网站的安全漏洞,比如:
- 中国电信某省任意用户登陆(可恶意扣费)
- 中石化某销售物流系统后台远程命令执行的服务器沦陷(客户信息泄漏&&可内网渗透)
- 盛大某游戏总管理权限泄露可随意更改游戏玩家数据
- 招商银行某服务器存在漏洞可Shell(穿透边界防火墙连通内网)
这里面包括了通信、金融、银行、能源、游戏等各个行业的Web应用的各种漏洞,有一些已经造成了影响广泛的严重安全事件,例如:CSDN、12306、小米用户信息泄露事件,携程网信息安全门事件、某快递官网遭入侵1400万条用户信息被转卖等等。
对于很多公司而言软件系统安全关注的重点还在网络和操作系统层面上,比如配置昂贵的网络入侵检测系统以等;很多开发人员安全意识薄弱,比如使用直接在代码中组装SQL语句,使用简单的数据加密和认证的方案,使用弱口令以及在产品中嵌入一些特定的调试信息;很多测试人员也不会进行基于业务流程的安全测试;系统管理和运维人员对于不可预知的应用组件和依赖的安全漏洞无法及时发现和修补。很多中小型公司基本不可能对于Web安全投入太多,比如无法在开发的过程中持续关注安全问题,从而导致系统上线之后还存在很多问题。因此,开发、测试和运维人员能充分理解安全的重要性以及掌握自动化安全扫描的方法和工具,对于开发一个安全的Web系统至关重要。
针对Web应用如此多的安全问题,全球范围内的有志之士成立了OWASP(Open Web Application Security Project),致力于宣传各种Web应用的安全问题。以及如何扫描、防御等知识,并且每2~3年还会发布世界范围内排名前十的安全问题。虽然OWASP提供如此丰富的安全知识,但是很多开发团队并没有充分利用,有些甚至还不知道,有些知道却不愿意投入。各种原因导致当前中国互联网上的众多Web应用拥有大量安全问题。
二.持续安全扫描
面对当前如此复杂和危险的互联网环境,如果一个在线金融系统(比如网银,P2P金融)存在安全问题,而系统管理员又没有及时发现安全问题和修复,那么时间越久,攻击者对其利用的程度越高,系统遭受的损失越大。这些安全问题可能是系统本身业务设计或者编码遗留的问题,也可能是依赖的第三方组件或者服务的问题。对于一些金融系统,修复安全漏洞哪怕只是晚几个小时,损失也可能是巨大的。如果不及时发现系统的安全问题并及时修复,那么开发成本和系统损失随着时间的推移可能会成指数级的增长。所以尽早发现安全问题并修复是节省成本和避免损失的有效方法。
对于软件安全,当前许多企业只会在发布或者上线之前进行一次渗透测试,如下图:
这种一次性的解决方案存在很多问题。其结果的有效性很难保证,如果发现问题可能会严重拖延发布时间等。为了解决它们,可以引入内建开发流程-BSI(Build Security In),如下图:
其中自动化的静态代码扫描,动态系统扫描,依赖扫描以及初级的渗透测试都可以比较容易的在CI中实现。示意图如下:
1. 静态代码扫描
利用静态代码扫描工具对代码在编译之前进行扫描,并在静态代码层面上发现各种问题,其中包括安全问题。部分工具列表:
工具 | 支持语言 | 版权 | 主页地址 |
---|---|---|---|
Fortify | 大部分语言 | 收费 | http://www8.hp.com/us/en/software-solutions/static-code-analysis-sast/ |
Checkmarx | 大部分语言 | 收费 | https://www.checkmarx.com/ |
Flawfinder | C/C++ | 免费 | http://www.dwheeler.com/flawfinder/ |
LAPSE | Java | 免费 | http://www.owasp.org/index.php/Category:OWASP_LAPSE_Project |
Brakeman | Ruby on Rails | 免费 | https://github.com/presidentbeef/brakeman |
利用动态安全扫描工具在系统部署之后对运行中的系统进行安全扫描。
2.动态安全扫描
动态扫描一般分为两种类型:主动扫描和被动扫描。
- 主动扫描是首先给定需要扫描的系统地址,扫描工具通过某种方式访问这个地址,如使用各种已知漏洞模型进行访问,并根据系统返回的结果判定系统存在哪些漏洞;或者在访问请求中嵌入各种随机数据(模糊测试)进行一些简单的渗透性测试和弱口令测试等。对于一些业务流程比较复杂的系统,主动扫描并不适用。比如一个需要登录和填写大量表单的支付系统,这个时候就需要使用被动扫描。
- 被动扫描的基本原理就是设置扫描工具为一个Proxy Server,功能测试通过这个代理服务访问系统,扫描工具可以截获所有的交互数据并进行分析,通过与已知安全问题进行模式匹配,从而发现系统中可能的安全缺陷。一般在实践中,为了更容易地集成到CI,会在运行自动化功能测试的时候使用被动扫描方法,从而实现持续安全扫描。示意图如下:
部分工具列表:
工具 | 扫描漏洞类型 | 版权 | 主页地址 |
---|---|---|---|
ZAP | 通用Web应用漏洞 | 免费 | https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project |
SQLMap | SQL注入 | 免费 | http://sqlmap.org/ |
Burp Suite | 通用Web应用漏洞 | 收费 | http://www.portswigger.net/ |
N-Stalker | 通用Web应用漏洞 | 收费 | http://www.nstalker.com/ |
3.依赖扫描与监控
虽然自动扫描工具可以发现大部分基本的Web安全漏洞,比如XSS,CSRF等,但是它不能发现业务逻辑、身份认证以及权限验证等相关的安全漏洞,而对于这些类型的漏洞则需要开发相应的自动化安全功能测试。
由于当前服务器应用依赖的第三方的库和框架越来越多、越来越复杂,比如SSL、Spring、Rails、Hibernate、.Net,以及各种第三方认证系统等。而且系统开发的时候一般选定某个版本后在很长一段时间内都不会更新,因为更新的成本一般都比较高。但是往往这些依赖为了添加新的功能和修复各种当前的问题——当然包括安全问题,却会经常更新。开源项目的安全问题只要被发现以后,通常都会被公布到网上去,比如CVE、CWE、乌云等,导致很多人都可能利用它去攻击使用这些依赖的系统。
依赖扫描就是通过扫描当前Web系统使用到的所有第三方依赖,并和网上公布的安全漏洞库进行比较,如果当前某个第三方依赖存在某种危险级别(需要自己定义)的漏洞,就立即发出警告(比如阻止CI编译成功等)来通知开发人员或者系统管理员,从而在最短的时间内修复这个问题,防止攻击,避免或者减少损失。示意图如下:
部分工具列表:
工具 | 漏洞数据源 | 版权 | 主页地址 |
---|---|---|---|
OWASP Dependency Check | NVD和CVE | 免费 | https://www.owasp.org/index.php/OWASP_Dependency_Check |
Victims | CVE和Redhat | 免费/收费 | https://victi.ms https://github.com/victims |
三. 在CI中实现自动化安全扫描
将这三种类型的自动化安全扫描实践集成到CI服务器中就可以实现对系统的持续性安全扫描。
1、在项目构建阶段进行依赖扫描与监控
对项目使用到的依赖进行安全扫描和监控是非常必要的,而将这一过程自动化能够进一步加强它的效果。这里以OWASP Dependency Check为例,介绍如何在项目构建阶段进行依赖扫描和监控。OWASP Dependency Check是一款开源免费的自动化依赖扫描工具,它由OWASP开发并维护,使用NVD和CVE作为漏洞数据源,自动识别依赖并扫描其是否存在安全问题。它提供Shell脚本、Ant插件、Maven插件和Jenkins插件。
以Maven插件为例,首先在pom.xml文件里添加这个插件 。
然后使用Maven对项目进行构建,OWASP Dependency Check插件会自动识别项目的依赖(包括间接依赖),对其进行安全扫描并生成报告。
在Jenkins中运行扫描并保存安全报告的配置如下:
下面的扫描报告中列出了Struts2和commons-fileupload两个依赖存在安全漏洞,以及严重程度等信息,如下图:
如果项目没有使用Maven, OWASP Dependency Check还提供Jenkins插件,同样能对依赖进行扫描,但这种方式需要明确指定所需扫描依赖的目录或者文件名,Jenkins配置如下:
OWASP Dependency Check以自动化的方式对项目的依赖进行扫描,极大的降低了人力成本、提高了效率。不过目前它仅能扫描JAVA和.NET项目的依赖,针对Node.JS、客户端JavaScript库的支持还处于计划阶段。另外,目前它没有提供Gradle的插件,如果您的项目使用的是Gradle,则只能用命令行的方式来运行它。
2、在自动化测试阶段进行被动方式的动态安全扫描
针对Web应用的安全扫描工具非常多,其中OWASP ZAP是免费软件里面最为常用的。虽然OWASP ZAP官方并没有提供相应的方案和构建系统以及CI进行集成,但是有一些第三方的开源工具可以帮助其集成。下面将以Gradle项目为例,介绍如何在CI自动化测试阶段集成ZAP并进行被动方式的动态安全扫描。
第1步:下载安装ZAP。
第2步:在Gralde构建脚本中配置security-zap插件用于集成ZAP。
第3步:配置WebDriver,为其设置代理。
默认配置下,security-zap插件在启动ZAP之后,ZAP会侦听本地7070端口,因此需要将WebDriver的代理设置为localhost:7070,参见示例代码18。
第4步:启动ZAP并运行测试。
使用zapStart命令来启动ZAP,用build来运行一次构建,在运行所有测试的同时进行被动扫描,命令如下:
gradle zapStart build -Dzap.proxy=localhost:7070
第5步:生成安全报告。
在所有的测试都执行完毕后,使用zapReport命令生成报告,命令如下:
gradle zapReport
它会在项目根目录下新建一个名为zap-reports的目录,并将安全扫描报告放置其中。下面是一份示例安全报告,它列出了所测试的Web应用的安全漏洞,按照严重程度以及类别进行了统计,还包含了每个安全漏洞的细节信息,报告如下:
第6步:关闭ZAP。命令如下:
gradle zapStop
第7步:Jenkins集成。Jenkins配置如下:
3、在测试环境部署阶段进行主动方式的动态安全扫描
继续以Gradle项目和OWASP ZAP为例,在安装好ZAP并且在构建脚本里配置好security-zap插件后(同上一阶段的步骤1、2), 只需要使用zapStart和zapScan命令就可以启动主动式扫描,命令如下:
gradle zapStart zapScan
主动扫描的检查能力更强,可以弥补被动扫描的不足,但缺点是耗时长,以及在扫描需要身份验证的系统的时操作复杂。
默认配置下主动扫描启动后,security-zap插件会主动检测扫描进度,默认扫描等待时间为60分钟。如果主动式安全扫描的执行时间超过了这一时间,security-zap会因为超时而终止运行,不过ZAP安全扫描并不会因此而停止,它还将继续运行,直到完成所有的安全扫描为止。若要了解当前扫描进度,可以通过运行zapScanStatus命令查询,命令如下:
gradle zapScanStatus
扫描完成后,通过运行下面的命令生成安全扫描报告,并关闭ZAP:
gradle zapReport zapStop
四. 总结
自动化持续Web安全扫描是一个复杂的课题,很大程度上依赖于自动化Web安全扫描工具的能力。当前绝大部分Web安全扫描工具并不能发现所有的安全问题,就算OWASP TOP10也无法全部包括,但是它可以在较小投入的情况下持续发现大部分Web系统的基础安全问题,从而防止大部分中级和几乎所有初级的黑客攻击。如果需要更高级别的安全保障,人工渗透性测试和威胁建模等必不可少,但是成本也是相对较高的。
所以对于Web系统的安全,首先要分析系统的安全需求和可用资源,在资源有限的情况下应该首先实施自动化持续安全扫描。如果系统的安全需求很高,并且在资源允许的情况下再投入人工渗透性测试等,从而获得安全上的最高投资回报比。