本论文相关内容
- 论文下载地址——Web Of Science
- 论文中文翻译——Automated Vulnerability Detection in Source Code Using Deep Representation Learning
- 论文阅读笔记——Automated Vulnerability Detection in Source Code Using Deep Representation Learning
文章目录
前言
本文是Automated Vulnerability Detection in Source Code Using Deep Representation Learning论文的阅读笔记,其中对于一些本文没有解析特别清楚或者默认没有解释的内容进行了自己的一些总结和理解。并且将论文的内容精炼,将其中的方法总结好,方便阅读和学习。在这篇论文里又能学习到新的漏洞检测的方法,和上一篇又有所不同。本文主要讲述了如何将源代码词法化以及使用卷积神经网络和递归神经网络配合随机森林对漏洞进行判断,对于漏洞检测的学习有很大的帮助。下面就是本片阅读笔记的全部内容!
基于深度表示学习的源代码漏洞自动检测
摘要
摘要部分作者主要是针对本文所提出的方法以及实验结果做了简要介绍。下面做简要总结:
- 本系统基于深度表示学习以及利用C和C++开发的大型函数级漏洞检测系统。
- 作者编译了包含百万开源函数的数据集,并且用三个不同静态分析器精心挑选的结果标记它。此数据集位于:https://osf.io/d45bw/。
- 该系统可以直接解释词法化的源代码。
- 通过实验表明,该系统在自动化软件漏洞检测方面很有前途。
索引术语
本文的关键字包括:
- 人工神经网络
- 计算机网络
- 数据挖掘
- 机器学习
I. 引言
引言部分的核心观点说明了当前漏洞检测工具的局限性:当前的漏洞检测工具仅根据预定义规则检测到有限的漏洞。这一点和上一篇分析的论文观点相似,因为人类专家定义的规则往往具有主观性从而导致漏洞检测的规则有很多不确定性因素。所以针对以上局限性,作者介绍了如何使用机器学习技术自动的检测C/C++源代码中的漏洞。
II. 相关工作
这部分论述了作者在引入本文所介绍的方法之前所做的工作,首先介绍了两种漏洞分析器:
- 静态分析器:无需执行程序即可运行。也就是通过自动化工具读取并分析程序的源代码,检测程序中可能存在安全漏洞的关键点。
- 动态分析器:在真实或虚拟处理器上重复执行带有许多测试输入的程序,以识别弱点。也就是在静态分析的基础上验证漏洞分析结果,提高漏洞挖掘的准确性。 动态分析主要包括以下几个步骤:
- 首先根据静态分析结果生成测试用例。
- 然后在安装应用程序的终端上执行测试数据,并进行污点分析,监控应用程序的异常行为
- 最后得到动态分析结果
这两种分析器都是基于规则的方法,也就是之前所介绍的基于人类专家手动定义的规则,这样无法保证检测的准确性,并且为了定义规则从而导致工作量很大,所以如何解决这种问题是本文的核心思想。
然后又说明了其他人在这方面所做的努力:
- Hovsepyan等人使用支持向量机(SVM)对一个简单的Java源代码标记化的单词包(BOW)表示进行预测,以预测静态分析器标签。
- Pang等人通过在SVM分类器使用的特征向量中包含n-gram扩展了这项工作。
- Mou等人通过嵌入源代码抽象语法树表示的节点,并针对简单的监督分类问题训练基于树的卷积神经网络,探索了程序分析的深度学习潜力。
- Li等人使用经过库/API函数调用相关代码片段训练的递归神经网络(RNN)来检测与这些调用的不当使用相关的两类漏洞。
- Harer等人训练RNN检测合成代码库中函数的词法表示中的漏洞,作为生成式对抗性代码修复方法的一部分。
根据以上分析,作者得出结论:目前没有人使用深度学习在大型自然代码库中的源代码检测漏洞,因为以往有限大小和种类的数据集限制了这种方法的有效性。所以就引出作者本文提出的观点:如何使用深度表示学习进行源代码漏洞自动检测。
III. 数据
因为深度学习需要大量的数据来训练模型,所以对于数据的选取就显得十分重要,不仅要选取合适的数据集,还要给数据集打标签,从而让我们的模型准确率更高,也让训练的模型直接从代码中有效地学习安全漏洞的模式。
本文所使用的数据集来自于SATE IV Juliet测试套件、Debian Linux发行版和GitHub上的公共Git存储库,其中都是C和C++的函数级示例数据集,数据集数量超过了1200万。汇总的有效数据集如下表所示:
这里可能有人会问,为什么几乎所有的源代码漏洞检测都是使用C/C++的数据集进行训练呢?其实也很简单,因为我们要检测的是程序/软件的漏洞,而程序/软件大多都是C/C++编写的。如果我们要进行Web的漏洞检测,那么肯定就是大多使用Java语言的数据集进行漏洞检测了。当然,这只是我目前的理解。
A. 源词法分析
在本文所提出的方法中,最重要的就是对原始源代码生成有用的特性,也就是如何对源代码生成C/C++词法,来捕获关键标记的相关含义,但是我们还要做到标记词汇表大小最小化。这样不仅可以使训练的模型准确,还可以使训练的速度比较快。同时还要注意不要对我们词法化的源代码生成太多的细节,因为变量太多可能会导致训练模型过程中的过拟合。
这里简单介绍一下过拟合的概念:过拟合是指随着训练过程的进行,模型的损失值在训练集上越来越小,但是在测试集上的损失值却越来越大(如下图所示)。说白了就是我们训练的模型只适合我们训练的数据,而不适合外界的数据。
过拟合产生的原因有以下几点:
- 训练集的数量级小于模型的复杂度。
- 训练集的测试集特征分布不一致。
- 训练集中的噪音数据干扰过大,导致让模型拟合了错误的特征。
过拟合的解决方案有以下几点:
- 减低模型复杂度。
- 增加训练集的数量。
- 使用正则化减低训练参数的数量。
- 使用DropOut使神经网络的神经元以一定的概率不工作。
对于源词法分析,作者提出以下几个准则:
- 词汇表总大小为156个标记。
- 词汇表中包括所有基本C/C++关键字、运算符和分隔符。
- 不影响编译的代码(如注释)被去除。
- 字符串、字符和浮点字被词法化为类型特定的占位符标记,所有标识符也是如此。
- 整数字是逐位标记化的,因为这些值通常与漏洞相关。
- 常见库中可能与漏洞相关的类型和函数调用被映射到通用版本。例如,u32,uint32_t,UINT32,uint32,和DWORD都被词法化表示为32位无符号数据类型的相同通用标记。
B. 数据管理
对于神经网络的训练,其中非常重要的一步就是删除重复数据,因为其对于我们的训练毫无帮助并且影响训练速度,在本文中,作者也提到了这一点,我们要删除训练集中潜在的重复函数。对于如何删除这些重复数据,作者也给出了方法:删除任何源代码的词法重复表示或编译级特征向量重复的函数。
表I的“通过管理”行反映了重复删除过程后剩余的函数数量,约占删除功能总数的10.8%。删除重复函数之后,可以明显的提高模型的性能。
C. 标签
对于如何给我们的原始数据打标签以形成有效的训练数据是一个重要内容 。作者指出,对原始数据打标签有三种方法:静态分析、动态分析和提交消息/错误报告标记。 其中由于动态分析非常耗费资源以及基于提交注释的标签提供低质量的标签的缺点。所以作者最终选择了静态分析,使用了三个开源静态分析器Clang、Cppcheck和Flawfinder。综合利用每个静态分析器的搜索和检测范围各不相同的特点,合并了三个静态分析器,并对其输出进行了删减,以排除通常与安全漏洞无关的发现,从而创建健壮的标签。而对于静态分析的过程,已经总结在上文了。
作者根据CWE生成关于源代码“易受攻击”和“不易受攻击的”二进制标签。例如:
- 数组访问越界被映射到CWE-805(长度值不正确的缓冲区访问),因为其可导致程序崩溃,所以被标记为“易受攻击”。
- 未使用的结构成员被映射到CWE-563(未使用的变量赋值),虽然这是一种糟糕的代码风格,但是由于其不会导致漏洞,所以被标记为“不易受攻击”。
表II显示了这些“易受攻击的”函数中频繁发生的CWE的统计数据。Debian和GitHub的所有开源函数源代码以及相应的CWE标签都可以在这里找到:https://osf.io/d45bw/。
IV. 方法
对于本文提出的机器学习漏洞检测方法,主要是将词法函数源代码的神经特征表示与强大的集成分类器随机森林(RF)相结合。整个过程如下图所示(文字描述见图片注释):
A. 神经网络分类与表示学习
在这部分作者主要针对本文提出的使用神经网络分类与表示学习应用于漏洞检测的整个过程,其实本文在这部分已经叙述的很详细了,下面我就做一个简短的总结,整个过程主要分下面几个步骤:
-
嵌入: 组成词法函数的标记首先嵌入到一个固定的 k k k维表示(限制在[- 1,1]范围内),经过实验发现, k k k=13对于有监督的嵌入大小表现最佳,平衡了嵌入的表达性和过度拟合。并且通过加入少量随机高斯噪声 N ( μ = 0 , σ 2 = 0.01 ) \mathcal{N}\left(\mu=0, \sigma^{2}=0.01\right) N(μ=0,σ2=0.01)对每个嵌入表示都大大提高了对过拟合的抵抗力,比其他正则化技术(如权重衰减)更有效。
-
特征提取:主要使用CNNs(卷积特征提取)和RNNs(递归特征提取)方法
-
卷积特征提取:使用形状为 m × k m×k m×k的 n n n个卷积滤波器。作者指出,当过滤器大小为 m = 9 m = 9 m=9时最有效。最终设置了 n = 512 n = 512 n=512个过滤器,再加上通过ReLU进行批量标准化,效果最好。
-
递归特征提取:为了捕获更长的标记依赖关系,使用递归神经网络进行特征提取。嵌入表示被馈送到多层RNN,在长度为 l l l的序列中每个步骤的输出被级联。作者最终使用隐藏状态大小为 n ′ = 256 n' = 256 n′=256的两层门控递归单元RNNs
-
-
池化:因为可能真实世界的C/C++函数长度不一,所以卷积和递归特征都会沿着序列长度 l l l被最大池化,以生成固定大小(分别为 n n n或 n ′ n' n′)的表示。这样在后续才能对其进行统一处理。
-
密集层:此部分位于特征提取层后,是一个完全连接的分类器。作者指出,在最终softmax输出层之前使用64和16的两个隐藏层可以获得最佳的分类性能。
-
训练:在训练过程中,作者指出了几项指导原则:
- 为了方便数据批处理,只训练标记长度为 10 ≤ l ≤ 500 10 ≤ l ≤ 500 10≤l≤500的函数,对于长度不足500的标记,需要填充到最大长度500。
- 卷积网络和递归网络的训练均采用批次大小128的Adam优化(学习率分别为 5 × 1 0 − 4 5 × 10^{−4} 5×10−4和 1 × 1 0 − 4 1 × 10^{−4} 1×10−4)。
- 具有交叉熵损失。
- 因为数据集不平衡,因此在损失函数中,易受攻击的函数权重更大。
- 使用数据集的80:10:10分割来训练、验证和测试模型。
- 根据最高的有效马修斯相关系数(MCC)调整和选择模型。
在这里补充马修斯相关系数(MCC)的相关概念: MCC是一个描述实际分类与预测分类之间的相关系数,它的取值范围为{-1,0,1}。
- 取值为1时表示对被测试对象的完美预测。
- 取值为0时表示预测的结果不如随机预测的结果。
- 取值为-1时表示预测分类和实际分类完全不一致。
因为MCC同时考虑了真阳性、真阴性和假阳性和假阴性,所以通常认为该指标是一个比较均衡的指标,即使是在两类别的样本含量差别很大时,也可以应用它。 基于MCC的这个特性,所以非常适合于测评本文所提出的模型。MCC计算公式如下所示:
M C C = T P × T N − F P × F N ( T P + F P ) ( T P + F N ) ( T N + F P ) ( T N + F N ) \mathrm{MCC}=\frac{T P \times T N-F P \times F N}{\sqrt{(T P+F P)(T P+F N)(T N+F P)(T N+F N)}} MCC=(TP+FP)(TP+FN)(TN+FP)(TN+FN)TP×TN−FP×FN
B. 神经表证的集成学习
在这部分作者指出,虽然神经网络方法会自动构建它们自己的特征,但是最终的分类效果却并不理想。但是作者发现使用神经特征(CNN中序列最大池卷积层的输出和RNN中序列的最大池输出状态)作为强大的集成分类器(如随机森林或极随机化树)的输入可以获得最佳分类效果。同时还可以防止过拟合,并且使训练分类器更加方便。
V. 结果
通过最终的测试结果,作者得出以下结论:
- CNN模型在独立分类器和特征生成器方面表现优于RNN模型。
- CNNs训练速度更快,所需参数更少。
- 基于神经特征表示训练的RF分类器在CNN和RNN特征方面均优于独立网络。
- 基于神经网络表示训练的RF分类器的性能优于基准BOW分类器。
对于模型的性能指标如下图表所示:
- 在测试集上的召回率如下图所示:
- 精确召回曲线下的面积(PR AUC)和接收器操作特性(ROC AUC)以及验证最佳阈值下的MCC和 F 1 F_{1} F1得分如下表所示:
- 分类器检测特定漏洞类型时的性能如下图所示:
- 模型在几乎标签平衡的数据集上的性能以及SA发现如下图所示:
- 各种模型和分类器在SATE IV数据集上的评测指标如下所示:
对比传统的静态分析工具,本文提出的机器学习方法有额外的优势,总结如下:
-
本文提出的定制词法器和机器学习模型可以快速消化和评分大型存储库和源代码,而无需编译代码。
-
由于机器学习方法都是输出概率,因此可以调整阈值以达到期望的精确度和召回率。
-
静态分析器会返回固定数量的结果,对于庞大的代码库来说,这些结果可能非常大,对于关键应用程序来说可能太小。而机器学习方法可以动态的调整结果大小。
-
机器学习方法不仅可以像静态分析器那样定位漏洞,还可以使用可视化技术,如下图所示的功能激活图,帮助理解算法做出决策的原因。
VI. 结论
在这部分作者主要对本文工作所做的贡献做了一个总结:
- 构建了一个广泛的C/C++源代码数据集。
- 创建了一个定制的C/C++词法器来创建一个简单、通用的函数源代码表示,非常适合机器学习训练。
- 使用通过卷积神经网络学习的特征和使用集成树算法进行分类,获得了最佳的总体结果。
同时作者也对未来在这方面需要做的工作做了简要总结:
- 未来的工作应该集中在改进的标签上,例如来自动态分析工具或从安全补丁中挖掘的标签。
- 本文中开发的用于直接学习函数源代码的机器学习技术也可以应用于任何代码分类问题,例如检测样式冲突、提交分类或算法/任务分类。
总结
以上就是本篇阅读笔记的全部内容。本文使用卷积神经网络学习的特征和集成树算法方法解决漏洞检测的准确性问题。基本思路是将源代码进行源词法分析从而提取到有用的特征。然后删除源代码的词法重复表示或编译级特征向量重复的函数,这样可以提高模型的性能。之后给处理好的数据打标签,分别标记为“易受攻击”和“不易受攻击”。最后将词法函数源代码的神经特征表示与强大的集成分类器随机森林(RF)相结合,具体分为:嵌入、特征提取、池化、密集层、训练五个步骤。最终得到了高准确率的漏洞检测结果。
本文所提出的方法的优点包括:
- 训练速度快
- 所需参数更少
- 性能高
- 准确率高
- 可以应用到任何代码分类问题(例如检测样式冲突、提交分类或算法/任务分类)
本文所提出的方法的缺点包括:
- 对于标签的分类较简单
- 不能考虑到所有情况
- 目前本文所提出的方法只适用于C/C++语言,而不适用于其他语言