软件安全测试新武器 ——浅谈基于Dynamic Taint Propagation的测试技术
软件安全测试是保证软件能够安全使用的最主要的手段,如何进行高效的安全测试成为业界关注的话题。多年的安全测试经验告诉我们,做好软件安全测试的必要条件是:一是充分了解软件安全漏洞,二是拥有高效的软件安全测试技术和测试工具。
一:安全主要漏洞与测试方法分析
软件安全保证的主要目的就是为了防止黑客或者恶意的内部人员对软件进行攻击,并保证软件在受到恶意攻击的情况能够正常运行。而攻击者主要是通过对软件系统输入恶意的数据来进行攻击。因此,软件主要的安全问题来源于外部的输入数据。开放性WEB应用项目安全组织OWASP Top Ten总结每年的全球WEB应用系统十大安全漏洞,其中最多的安全漏洞就是来自外部输入数据的验证方面。全球最大的软件安全厂商Fortify Software公司的软件安全漏洞分类中安全风险最高的安全漏洞也是输入验证与表现这个方面。由外部输入恶意数据可以直接构成严重的软件安全漏洞主要有:
- 命令注入(Command Injection)
- 跨站脚本(Cross-Site Scripting)
- 拒绝服务(Denial of Service)
- HTTP响应截断(HTTP Response Splitting)
- 路径操纵(Path Manipulation)
- 资源注入(Resource Injection)
- 配置操纵(Setting Manipulation)
- SQL注入(SQL Injection)
- 访问控制:数据库(Access Control: Database)
- 日志伪造 (Log Forging)
所以做好外部输入数据安全测试是软件安全测试中最重要的工作,那么目前主要安全测试方法有:
1.静态的代码安全测试:主要是通过对软件系统的源代码进行安全扫描,根据程序中数据流,控制流,语义等信息与其特有软件安全规则库进行匹对,从中找出代 码中潜在的安全漏洞。静态的源代码安全测试是非常有用的方法,它可以在编码阶段找出所有可能存在安全风险的代码,这样开发人员可以在早期解决潜在的安全问 题。而正因为如此,静态代码测试比较适用于早期的代码开发阶段,而不是测试阶段。同时,由于关系到开发部门,测试部门,管理部门等多个部门的工作,在实际 的贯彻实施工作上有一定的难度。
2.动态的渗透测试:渗透测试也是我们常用的安全测试方法。使用自动化工具或者人工的方法模拟黑客的输入,对应用系统进行攻击性测试,从中找出运行时刻所 存在的安全漏洞。这种是测试的特点就是真实有效,一般找出来的问题都是正确的,也是较为严重的。但渗透测试一个致命的缺点就是,但由于模拟的测试数据只能 到达有限的测试点,覆盖率很低。根据美国权威机构统计,渗透测试的覆盖率只能达到20%-30%。漏报率比较高。
二:Dynamic Taint Propagation方法
分析两种常用的安全测试的方法,对于外部输入数据的测试都有一定的不足之处,那么如何才能对外部输入数据进行较好的安全测试呢?业界提出了动态污染传播的方法(Dynamic Taint Propagation)。
动态污染传播方法,主要通过跟踪外部输入的数据在程序中的传播过程,和最终执行的情况来分析是否存在安全漏洞和存在什么类别的漏洞。如下图1,它不需要任 何特殊的攻击性的测试数据,它假定由外部输入的数据都是不可信的、污染的数据,为数据打上污染的标记,在程序中传播的过程中,如果经过了严格的,我们可以 依赖的安全验证,我们就认真它不再是污染的,掉去污染标记,否则污染标记在整个传播过程都会被继承下来。一旦有污染标的数据被送到执行代码中执行的时候就 判断这里可能存在一个安全漏洞。
图1:污染数据的传播过程图
实现动态污染传播方法来进行测试,首先要对软件程序所有二进制码进行静态地分析,主要是指定以下信息:
Source:污染数据的来源。找出所有外部数据进行程序的入口的代码。对于WEB应用系统,主要是指读取客户端输入的数据的地方:如HTML的Form 表单,用户的Request的参数,客户端的Cookie信息等这些接收外部数据方法。当数据由这些入口点进行程序内部时,数据假定是污染的,被标记上污 染标记。
Propagation:污染数据传播。数据在程序中传播的过程中,当数据从Source点传入,标记上污染标记,污染数据在程序中传播的过程中,无论是被赋给另一个数据,被拼接到另一个数据之中,污染标记都要被继承下来。
Sink:漏洞的引爆点。找出所有可能引发安全漏洞的代码。这些代码常常是根据外部传入数据而执行特定任务的代码。如SQL的查询,HTML中输出,命令 的执行等等。当数据被传到Sink代码时,Sink首先去检查此数据是否带有污染标记,如果没有,则没有安全问题。反之,则此处可能存在安全问题。然后再 根据代码执行的结果来判定是什么类别的安全问题。举例来说明这一分析过程:
userID = request.getParameter("user");
……
2
try {
sql = "SELECT * FROM users " +"WHERE
id='" + userID + "'";
……
stmt.executeQuery(sql);
}
这段代码在静态分析过程中,request.getParameter()方法会被标记为一个 “污染源”: Source。stmt.executeQuery()方法会被标记为一个“引爆点”:Sink。当用户输入数据“user”通过 request.getParameter()进入程序并赋值予变量“userID”时, “userID”会被标记上“污染”标记。当用 “userID” 来构造变量“sql”时,“sql”会获取“userID”的“污染”标记而成为被“污染”的数据。当“sql”被送到Sink函数 stmt.executeQuery()中执行的时候,Sink函数的检测机制检测到了“sql”有污染标记,从而判定此处可能引发一个安全问题,随后再 根据Sink函数执行“污染”数据“sql”的结果,这里是执行一个SQL查询命令,依此可以判定此处可能会引发一个SQL—Injection的安全问 题。
三:Fortify Tracer
全球最大的软件安全厂商美国Fortify Software公司在根据从事多年的软件安全领域的研究的基本上,根据上文讲述的动态污染传播的方法(Dynamic Taint Propagation)成功开发出来了新型安全测试产品——Fortify Tracer。
图2:Fortify Tracer 安全测试报告
Fortify Tracer 利用动态污染传播方法的特点,首先对软件的二进制代码进行插桩分析,找出所有的Source, Sink代码,建立检测机制。然后再对程序进行常规的功能测试。测试过程不需要测试人员输入任何带攻击性的测试数据,就可以进行安全测试了,Fortify Tracer会根据功能测试自动地找出软件中所有可能因外部输入数据而造成的安全问题,并根据漏洞类类清晰地报告出来。总结Fortify racer的主要特点有:
1.无需特殊的攻击性测试数据,让QA人员都可以做安全测试。解决测试缺乏安全知识,攻击知识的难题。
2.由于直接跟踪外部输入数据,所以能够很真实、有效地找出系统中最严重,最关键的安全问题。
3.与功能并行,速度快,效率高,很容易与现有测试流程结合。同时利用功能测试覆盖率高的优点,大大提高了动态安全测试
的覆盖率。
4.清晰而详细的报告。如上图2所示,Fortify Tracer根据漏洞类别清晰地报告出来,点击报出的每一个漏洞,Fortify Tracer可以定位到该漏洞在什么地方产生的。它的Source和Sink分别在哪里等清晰而又详细的报告。
四、总结:
良好的测试方法加上优秀的测试工具一定能够更好地帮助软件企业做好软件安全测试。对于一个软件企业,如果能将软件质量测试与软件安全测试有效地结合,不但能很好地解决软件安全测试问题,同时也可以使得测试团队的工作效率更高,那么基于Dynamic Taint Propagation测试方法的Fortify Tracer将是一个不错的选择。