最近,他们越来越多地谈论静态分析,这是确保正在开发的软件产品的质量的重要手段之一,尤其是从安全性角度而言。 静态分析使您能够发现漏洞和其他错误,它可以在开发过程中使用,并集成到自定义过程中。 然而,关于其应用,出现了许多问题。 付费工具和免费工具有什么区别? 为什么用短绒还不够? 最后,统计信息与它有什么关系? 让我们尝试找出答案。

让我们立即回答最后一个问题-统计数据与它无关,尽管静态分析通常被错误地称为统计数据。 该分析是静态的,因为该应用程序在扫描期间不会启动。
首先,让我们弄清楚我们想要在程序代码中寻找什么。 静态分析最常用于搜索漏洞-代码段,其存在可能导致违反信息系统的机密性,完整性或可用性。 但是,可以使用相同的技术来搜索其他错误或代码特征。
我们保留一点,即通常来说静态分析的问题在算法上是无法解决的(例如,通过赖斯定理)。 因此,您必须限制任务的条件,或者允许结果不准确(跳过漏洞,提供误报)。 事实证明,在实际程序中,第二个选项确实有效。
有许多付费和免费工具声称可以用不同编程语言编写的应用程序中的漏洞搜索。 让我们考虑一下静态分析器通常是如何安排的。 此外,我们将专注于分析仪核心和算法。 当然,这些工具的界面友好性,功能集,针对不同系统的插件集以及API的易用性可能会有所不同。 这可能是另一篇文章的主题。
中级演讲
静态分析仪的操作方案可以区分三个基本步骤。
- 构建中间表示(中间表示也称为内部表示或代码模型)。
- 静态分析算法的使用,因此代码模型将补充新的信息。
- 将漏洞搜索规则应用于增强的代码模型。
不同的静态分析器可以使用不同的代码模型,例如,程序源代码,令牌流,解析树,三地址代码,控制流程图,字节码(标准或本机)等。

与编译器一样,词法分析和句法分析用于构建内部表示形式,最常见的是分析树(AST,抽象语法树)。 词法分析将程序文本分解为最少的语义元素,在输出处接收令牌流。 解析会验证令牌流是否与编程语言的语法相匹配,即,从语言的角度来看,所得的令牌流是否正确。 解析的结果是构建了一个解析树-一种对程序的源代码进行建模的结构。 接下来,应用语义分析;它检查更复杂条件的满足,例如,分配指令中数据类型的对应性。
解析树可以用作内部表示。 您还可以从分析树中获取其他模型。 例如,您可以将其转换为三个地址的代码,进而构建一个控制流程图(CFG)。 通常,CFG是静态分析算法的主要模型。

在二进制分析(二进制或可执行代码的静态分析)中,还建立了一个模型,但是此处已经使用了逆向工程实践:反编译,反混淆,反向翻译。 结果,您可以获得与源代码相同的模型,包括源代码(使用完全反编译)。 有时二进制代码本身可以用作中间表示。
从理论上讲,模型与源代码越接近,分析的质量就越差。 在源代码本身上,您只能搜索正则表达式,这将使您至少找不到任何复杂的漏洞。
数据流分析
数据流分析是主要的静态分析算法之一。 该分析的任务是在程序的每个点上确定一些有关代码所操作的数据的信息。 该信息可以是不同的,例如,数据类型或值。 根据需要确定的信息,可以制定分析数据流的任务。

例如,如果有必要确定一个表达式是否是一个常数以及该常数的值,则解决传播常数(常数传播)的问题。 如果有必要确定变量的类型,那么我们可以谈谈类型传播的问题。 如果您需要了解哪些变量可以指向特定的内存区域(存储相同的数据),那么我们正在谈论同义词分析(别名分析)的任务。 静态分析器中可以使用许多其他数据流分析任务。 像构建代码模型的步骤一样,这些任务也用在编译器中。
在构造编译器的理论中,描述了对数据流进行过程内分析问题的解决方案(有必要在单个过程/函数/方法中跟踪数据)。 决策基于代数格理论和数学理论的其他元素。 如果问题的条件满足可溶性定理的条件,则可以在多项式时间内(即计算机可接受的时间)解决分析数据流的问题,而这种情况在实践中并不总是发生。
我们将告诉您更多有关解决数据流的过程内分析问题的信息。 要设置特定任务,除了确定所需的信息外,还需要确定根据CFG中的指令传递数据时更改此信息的规则。 回想一下,CFG中的节点是基本块-指令集,其执行始终是顺序的,并且弧线指示基本块之间可能的控制转移。
对于每条指令
集定义:
- (指令生成的信息 ),
- (信息被指令破坏 ),
- (说明前一点的信息 ),
- (指示后的时间点的信息 )
数据流分析的目的是定义集合
和
每条指令
程序。 通过以下关系式(数据流方程式)确定解决这些数据流分析任务的基本方程组:
第二种关系制定了在CFG弧的汇合点“合并”信息的规则(
-前辈
在CFG中)。 可以使用并集,相交和其他一些运算。
所需的信息(上面介绍的函数值的集合)形式化为代数格。 功能介绍
和
被视为晶格上的单调映射(流函数)。 对于数据流方程,解决方案是这些映射的固定点。
解决数据流分析问题的算法会寻找最大的固定点。 解决方案有几种方法:迭代算法,强连接组件的分析,T1-T2分析,区间分析,结构分析等。 这些算法的正确性有一些定理;它们确定了它们对实际问题的适用范围。 我再说一遍,定理的条件可能无法满足,这导致算法更加复杂和结果不准确。
过程间分析
在实践中,有必要解决数据流的过程间分析问题,因为很少会将该漏洞完全局限在一个功能中。 有几种常见的算法。
内联函数 。 在函数调用点,我们嵌入了被调用函数,从而将过程间分析的任务减少到过程内分析的任务。 这种方法很容易实现,但是在实践中,应用该方法可以快速实现组合爆炸。
构造程序控制流的一般图形,其中函数调用由到调用函数的起始地址的转移替换,返回指令由到所有用于调用此函数的指令之后的所有指令的转移替换。 这种方法增加了许多无法实现的执行路径,从而大大降低了分析的准确性。
一种与上一个算法相似的算法,但是在切换到功能时,
将保存上下文 (例如,堆栈帧)。 因此,解决了创建无法实现的路径的问题。 但是,该算法适用于呼叫深度有限的情况。
建筑物功能信息(功能摘要)。 最适用的过程间分析算法。 它基于每个函数的摘要的构造:应用此函数时,有关数据信息的转换规则,具体取决于输入参数的各种值。 现成的摘要用于功能的内部过程分析。 这里的另一个困难是确定函数遍历的顺序,因为在逐案分析中,应该已经为所有调用的函数构造了一个摘要。 通常,会创建用于遍历调用图的特殊迭代算法。
过程间数据流分析是一项艰巨的任务,这就是分析器需要进行许多优化和假设的原因(不可能在足够的时间内找到准确的解决方案来提高计算能力)。 通常,在开发分析仪时,有必要在消耗的资源量,分析时间,误报数量和发现的漏洞之间找到折衷方案。 因此,静态分析仪可以长时间工作,消耗大量资源并产生假阳性结果。 但是,没有这个,就不可能找到最重要的漏洞。
正是在这一点上,严肃的静态分析器不同于许多开放式工具,这些工具尤其可以使自己处于寻找漏洞的位置。 当您需要快速获得结果(例如在编译过程中)时,在线性时间中进行快速检查非常有用。 但是,这种方法无法找到最关键的漏洞,例如与数据实现有关的漏洞。
污染分析
我们还应该专注于数据流分析的任务之一-污点分析。 污点分析使您可以在整个程序中分发标志。 此任务是信息安全的关键,因为借助它,发现了与数据实现(SQL注入,crossite脚本,开放重定向,伪造文件路径等)以及机密数据泄漏(密码输入)有关的漏洞。事件日志,不安全的数据传输)。
让我们尝试模拟一个任务。 假设我们要跟踪n个标志-
。 很多信息将是很多子集
\ {f_1,...,f_n \} ,因为我们要为程序中每个点的每个变量定义其标志。
接下来,我们需要定义流函数。 在这种情况下,可以通过以下考虑确定流量函数。
- 给出了许多规则,其中定义了导致出现或更改一组标志的构造。
- 分配操作将标记从右向左翻转。
- 规则集未知的任何操作都将合并所有操作数的标志,并将最后一组标志添加到操作结果中。
最后,您需要定义在CFG弧的交点处合并信息的规则。 合并由并集规则确定,也就是说,如果单个变量的不同标志集来自不同的基块,则在合并时将它们合并。 包括误报来自此处:算法不能保证可以执行指向出现标志的CFG的路径。
例如,您需要检测诸如SQL注入之类的漏洞。 当来自用户的未验证数据落入使用数据库的方法时,将发生此漏洞。 必须确定数据来自用户,并将污点标记添加到此数据。 通常,分析仪的规则库会设置用于设置异味标记的规则。 例如,将一个标志设置为Request类的getParameter()方法的返回值。

接下来,假设可以验证数据并且标志可能在执行路径之一上消失,则需要使用污点分析在整个分析程序中分配标志。 分析仪设置了许多删除标志的功能。 例如,从html标记验证数据的功能可以清除跨站点脚本(XSS)漏洞的标记。 或者,将变量绑定到SQL表达式的函数会删除用于嵌入SQL的标志。
漏洞搜索规则
应用上述算法的结果是,中间表示法补充了搜索漏洞所需的信息。 例如,在代码模型中,将显示有关哪些变量属于某些标志,哪些数据恒定的信息。 漏洞搜索规则是根据代码模型制定的。 这些规则描述了最终过渡视图中的哪些功能可能指示漏洞。
例如,您可以应用漏洞搜索规则,该规则定义带有带有taint标志的参数的方法调用。 返回到SQL注入的示例,我们验证带有taint标志的变量是否不属于数据库查询功能。
事实证明,除了算法的质量外,静态分析器的重要组成部分还包括配置和规则库:对代码中的哪些构造会生成标记或其他信息的描述,对这些数据进行验证的构造以及对使用这些数据的构造的描述至关重要。
其他方法
除了数据流分析之外,还有其他方法。 符号执行或抽象解释是其中之一。 在这些方法中,程序在抽象域上运行,计算和分布程序中的数据限制。 使用这种方法,不仅可以找到漏洞,还可以在输入数据上计算漏洞可被利用的条件。 但是,这种方法有严重的缺陷-实际程序中的标准解决方案,算法呈指数级爆炸,而优化导致分析质量的严重损失。
结论
最后,我认为有必要总结一下静态分析的利弊。 我们将逻辑分析与动态分析进行比较是合乎逻辑的,在动态分析中,漏洞搜索是在程序执行期间进行的。

静态分析的优点无疑是完整覆盖了所分析的代码。 同样,静态分析的优势包括以下事实:无需进行任何操作即可在战斗环境中运行应用程序。 静态分析可以在开发的早期阶段进行,从而将发现的漏洞的成本降至最低。
静态分析的缺点是不可避免会出现误报,资源消耗以及对大量代码的漫长扫描时间。 然而,基于算法的细节,这些缺点是不可避免的。 如我们所见,快速分析器将永远找不到真正的漏洞,例如SQL注入等。
我们在
另一篇文章中写到了使用静态分析工具仍然存在的困难,事实证明,可以很好地克服这些问题。