基于机器学习的漏洞检测高影响因素实证研究

 

摘要

Ahstract-Vulnerability检测是软件工程中的一个重要课题。为了提高漏洞检测的效果和效率,许多传统的基于机器学习和基于深度学习的漏洞检测方法被提出。然而,不同因素对漏洞检测的影响是未知的。例如,分类模型和矢量化方法会直接影响检测结果,代码替换会影响漏洞检测的特征。我们进行对比研究,评估不同分类算法、矢量化方法和用户自定义变量和函数名称替换的影响。在本文中,我们收集了三个不同的漏洞代码数据集。这些数据集对应着不同类型的漏洞,并且有不同比例的源代码。此外,我们对漏洞代码数据集的特征进行了提取和分析,以解释一些实验结果。从实验结果来看,我们的发现可以总结为以下几点。(一)使用深度学习的性能优于使用传统的机器学习,BLSTM可以达到最好的性能。(二)CountVectorizer可以提高传统机器学习的性能。(三)不同的漏洞类型和不同的代码来源会产生不同的特征。我们使用随机森林算法来生成漏洞代码数据集的特征。这些生成的特征包括系统相关函数、语法关键字和用户定义名称。(四)没有用户定义变量和函数名称替换的数据集将取得更好的漏洞检测效果。

 

第一节 导言

软件安全问题一直是软件工程领域的重要组成部分。有很多网络攻击都是以软件漏洞为根源的,并造成了巨大的损失[1]。虽然已经提出了很多检测软件漏洞的方法,但在常见漏洞和暴露(CVE)中报告的漏洞数量仍在增加[2]。看来,人类专家和项目管理技术的效果是有限的。它促进了结合机器学习的代码分析技术的发展。

代码分析技术主要有两类:动态代码分析和静态代码分析。动态代码分析需要对各种指标进行实时监控。因此很难使用机器学习算法来提高分析效率。动态分析工具[3]更多用于性能测试和功能测试。但静态分析工具如Clang[4]、Cppcheck[5]和Flawfinder[6]通常用于检测潜在的漏洞。但是现有的检测漏洞的解决方案会产生很高的假阴性率。因此,现有的关于漏洞检测的研究大多是基于静态代码分析和机器学习(即传统的机器学习[7]、[8]或深度学习[9])的结合。静态代码分析和漏洞检测有两个不同的层次:函数层次和代码层次。当在函数层面进行分析时,Tommy等[7]关注的是文件依赖性和项目复杂度。在代码层面分析时,Zhen等人[9]关注的是代码中的变量和逻辑。经验表明,与函数级分析相比,代码级分析的检查粒度更细,漏洞检测效果更好。

Zhen等人[9]提出了一种名为VulDeePecker的漏洞检测工具。VulDeePecker包括一套基于数据流的处理程序,以生成代码小工具。代码小工具是一种代码片,它包含了几乎所有的函数调用、变量和少量的噪声。它保留了源码的信息。因此,问题已经从如何分析代码转变为如何更好地对代码进行预处理。在VulDeePecker中,在训练深度学习模型的数据之前,需要执行两步。第一步是用户自定义变量和函数替换。在这一步中,用户定义的变量和函数的名称将被替换为通用名称。第二步是矢量化。VulDeePecker使用Word2vec工具[10]将行转化为向量。然后VulDeePecker使用双向长短期记忆(BLSTM)神经网络来训练分类模型。所以有四个关键点值得研究:

VulDeePecker只使用BLSTM作为训练模型,缺乏对其他机器学习模型的测试。我们想知道其他深度学习和传统机器学习模型是否也能提高漏洞检测的效果。
在自然语言处理领域,有很多文本矢量化方法。VulDeePecker使用Word2vec工具将代码转化为向量,但由于维度问题,向量必须被截断。我们能否找到一种更好的向量化方法,可以提高分类结果?
深度学习模型的内部结构很难解释,而传统的一些机器学习算法却可以解释。通过使用特征提取算法,我们可以得到漏洞的特征。这些特征可能会显示出一些规律性的模式,可以帮助我们分析和解释实验结果。
VulDeePecker替换了用户定义的变量和函数的名称。看起来这一步可以去除多余的噪声,提高模型的泛化能力。但这一步骤是否会导致一些可用信息的丢失还是未知数。

我们的贡献

在本文中,我们进行了一项比较研究,以评估不同因素的影响,包括分类模型和预处理方法。我们验证了这些因素对三种类型的脆弱性的影响。具体来说,我们的贡献可以总结为以下几点。

首先,我们整理了基于机器学习的漏洞检测框架,并选择分类模型、向量化方法和用户自定义变量和函数名称替换作为研究的主要因素。

其次,我们基于真实项目的数据集进行了大规模的对比研究,并对数据集进行了特征提取。我们将一些有趣的发现总结如下。(一)BLSTM模型在漏洞检测上表现最好。基于深度学习的漏洞检测整体效果优于传统机器学习。(二)对于传统的机器学习,CountVector-izer工具[11]是漏洞检测中最有效的矢量化方法。(三)从漏洞中提取的特征包含与人类经验相似的关键词,提取结果会受到代码数据来源和预处理方法的影响。(四)没有用户自定义变量和函数名称替换的数据集的实验结果较好。

第三,我们按照与[9]相同的方法收集包含新漏洞类型的数据集。在本文的实验中,除了使用[9]中的缓冲区错误漏洞和资源管理错误漏洞的数据集外,我们还收集并使用了资源管理错误漏洞的数据集。

论文组织
第二节是对基于机器学习的漏洞检测、预处理方法和分类模型的简单介绍。第三节阐述了我们实验设计的细节和我们使用的数据集。第四节介绍并讨论了我们的实验结果。第五节回顾了相关工作。第六节提出研究结论,并讨论未来的工作。

 

第二节 基于机器学习的漏洞检测

A. 基于机器学习的漏洞检测框架

基于机器学习的漏洞检测主要分为以下几个步骤。首先,我们通过基于数据流的代码分析方法生成代码小工具,并对其进行标注。代码小工具是预处理和模型训练的基本单元。其次,我们通过删除所有非ASCII字符和注释来清理数据集。我们还用通用名称替换用户定义的变量和函数名称。这一步是我们实证研究中考虑的因素之一。第三,我们将这些Code小工具转化为向量。最后,我们将数据集分为测试集和训练集来训练和评估模型。图2是基于机器学习的漏洞检测的整体框架。

图1.基于机器学习的漏洞检测框架

B. 替换函数名和变量名

在第一节中,我们提到了替换用户定义函数和变量名称的步骤。由于本文中使用的许多程序源码来自真实的软件产品,即使删除了代码注释,数据集仍然有很多噪声。在软件开发中,为了提高代码的可读性,往往会给这些代码中的变量和函数起一些有意义的名字[12]。虽然这些名称包含了很多信息,但它们也是多种多样的。噪声的主要来源就是这些名称。在[9]中,用户定义的函数和变量的名称被替换为通用名称。例如,在代码中有两个用户定义的变量(如userstr,usernum)和两个用户定义的函数(如Num-fun,Strfun)。这些名称将被转换为var1、var2、Fun1和Fun2。然而,名称替换的过程是相互独立的,在一个代码中的替换不会影响另一个代码。

在本文中,我们想研究这一步对数据集的具体影响。我们想知道替换是否可以降低噪声以提高模型泛化,以及替换是否会导致代码信息丢失。我们将通过特征提取和模型对比来证明这两个问题。

C. 文本向量

为了将训练代码数据输入分类模型,我们必须将代码转化为向量。这一步实际上是一种自然语言处理技术[13],[14]。在本文中,我们比较了三种不同的向量化方法:Index-based vectorization、CountVectorizer和Word2vec。

Index-based vectorization是最简单的方法。这种方法会将一个词转换成一个数字。不同的字对应不同的数字。所以说,包含多个字的代码可以转化为向量。但显然,向量的长度是不稳定的。如果使用这种方法,我们需要通过填充和截断向量来进行调整,因为分类模型是以等长的向量作为输入的。

CountVectorizer是一种字袋模型。CountVec-torizer通过计算整个训练数据集中的词频来构建向量。CountVectorizer首先通过数据集建立词库。词库中的词数也就是向量的长度。所以向量是对齐的。向量中的一个维度对应一个词,一个向量中的内容就是每个词在一个代码中的频率。这种方法保留了代码中所有的词,但失去了词序信息。

Word2vec在文本挖掘[15]和软件工程[16]中得到了广泛的应用。这种文本矢量化技术可以将一个词转化为一个与这个词意义相近的矢量。两个向量的距离越大,两个词的意义就越不同。所以Word2vec经常被用于文本情感分析。我们将这些词的向量合并成一个较长的向量来表示代码。显然,较长向量的长度也是不稳定的。我们需要做与上一节相同的调整。

D. 分类模型

本研究就是利用机器学习算法对代码进行分类,检测漏洞。我们用来比较的分类算法也分为两类。表一列出了实验中使用的所有算法。

传统的机器学习因其解释力强、时间性能好而被广泛使用。在我们的实验中,有两种集合学习模型和三种简单的传统机器学习模型。我们选择随机森林(RF)和梯度提升决策树(GBDT)作为集合学习部分,选择K-最近邻(KNN)、支持向量机(SVM)和逻辑回归(LR)作为简单机器学习部分。在这些算法中,RF和GBDT在训练模型时具有保留特征的能力。基于决策树的机器学习模型会在训练过程中自动对数据集特征进行评分。这为我们在特征提取部分的实验提供了算法支持。

表一 实验中使用的分类算法

深度学习常用于自然语言处理和软件工程领域[17]。虽然模型的内部结构很复杂,但深度学习模型总能在分类任务上取得良好的效果。VulDeePecker使用BLSTM对代码进行分类并检测漏洞。在此基础上,我们增加了两种新方法进行对比实验。卷积神经网络(CNN)和Gated Recurrent Unit(GRU)。

 

第三节 实验设置

A. 数据集

在本文中,我们主要从两个来源收集数据集:国家漏洞数据库(NVD)[18]和软件保障参考数据集(SARD)[19]。每个漏洞都有一个通用漏洞和暴露IDentifier(CVE ID)和一个通用弱点列举IDentifier(CWE ID)。我们可以通过CVE ID找到漏洞的详细信息,并通过CWE ID搜索漏洞的类别。在NVD中,我们可以找到每个漏洞的详细信息(包括漏洞的CWE ID)及其源代码,但不是每个漏洞都有相应的补丁和修复。在SARD中,每个程序可能对应一个或多个CWE ID,因为一个程序中可能存在多个漏洞。我们使用了三个不同的漏洞数据集:缓冲区错误漏洞(CWE 119)、资源管理错误漏洞(CWE 399)和不当的资源寿命控制(CWE 664)。前两个数据集可以直接从[9]中获得,第三个数据集需要从NVD和SARD中收集,然后以VulDeePecker的方式生成代码小工具。

为了给这些数据打上标签,我们使用的标签方法与[9]类似但不完全相同。对于来自NVD的程序数据,我们通过比较相应的补丁和源代码来标记它们。这一步与[9]中描述的相同。然而,对于来自SARD的数据,在标签上有一个区别。SARD中的每个程序都已经被贴上了好、坏和混合的标签。有good和bad的程序代表该程序是否存在漏洞。但混合的程序比较特殊,因为它既包含漏洞实现,又包含修复。在[9]中,好的程序被标记为 “0”,混合和坏的程序都被标记为 “1”。我们认为这种混合程序的标签方法有些随意,可能会造成标签的错误。因此,我们先人工将混合程序分离出来,按函数名将整个程序变成漏洞实现部分和修复部分,然后分别给每个部分打上标签。显然,这样会增加程序和代码小工具的数量。

表二 实验用数据集

表二是本实验中的数据集。可以看出,与[9]相比,由于标注方法的不同,CWE 119和CWE 399的量有一些变化。表二还显示了各数据集的来源比例。值得一提的是,在CWE 119数据集中,来自SARD的数据比例为64.5%,在CWE 399数据集中,来自SARD的数据比例为74.4%。但在CWE 664数据集中,来自SARD的数据比例为85.8%。我们也注意到NVD的代码和SARD的代码有一些不同。NVD的代码并不是直接储存在网站数据库中。NVD提供了很多代码源的定向链接。这些链接都指向真实的软件代码。但SARD中的代码则存储在美国国家标准与技术研究所(NIST)的在线数据库中。为了尽可能多的收录漏洞,SARD中的很多代码都是为了重现特定的漏洞而编写的。SARD中的开发人员会改变不同的控制流和数据流来重现漏洞。因此,这部分代码的针对性会更强,彼此之间的相似度也会更高。

B. 模型评价方法

在实验中,分类算法的性能与数据集的分割结果密切相关。虽然可以将数据集随机分为测试集和训练集,但仅仅一次实验的结果还是会出现意外。因此,本文为了提高分类模型的泛化能力,减少过拟合,我们将采用随机处理技术对数据集进行随机划分,多次运行分类算法。

在实验中,我们选择直接对数据集进行洗牌,然后将原始数据集随机划分为训练集和测试集。这种方法可以保证训练集和测试集的长度足够。为了减少事故的影响,必须有足够的迭代次数来洗牌和分配数据集。我们需要记录不同模型的所有性能。

在重复多次洗牌和数据集划分后,对于每个模型,我们可以得到一组分类性能测量结果。最终的评估结果将是这些性能测量结果的平均值。整个评估过程由算法1所示。特征提取实验与上述过程类似。反复对数据集进行洗牌,我们可以得到多个模型和多个特征提取结果。本文中,我们将多个结果的交集作为特征提取的最终结果。

算法1 算法评估过程

C. 分类业绩措施

漏洞检测是一项二元分类任务。我们使用混淆矩阵,它是大多数分类性能测量的起点。在做二元分类模型进行预测时,混淆矩阵可以记录四种可能的情况(见表二)。它通常用于计算其他指标。

表三 混淆矩阵

本文采用召回率(R)、精度(P)、F1-score(F1)、假阳性率(FPR)和假阴性率(FNR)来评价实验结果。本文中所有的测量指标都可以通过混淆矩阵计算出来。

Recall率衡量的是预测正例的能力,它是对覆盖率的衡量。Recall是真阳性样本与被正确分类的总样本的比值。

表四 分类模型在漏洞检测上的表现

精确率是针对我们的预测结果而言的,它表示在预测为阳性的样本中,有多少是真正的阳性样本。精确率的定义是真阳性样本除以被检测为真阳性的总样本的比例。

F1-score综合考虑精度和假阴性率的整体效果。它是最常用的机器学习性能指标之一。F1-score是Recall和Precision的谐波平均值。

假阳率(FPR)是指假阳性样本与不易受影响的总样本之比,假阴率(FNR)是指假阴性样本与易受影响的总样本之比。FPR和FNR代表预测误差的比率

 

第四节 实验结果与分析

A. RQ1:不同的机器学习模型如何影响漏洞检测的性能?

在第一节,我们介绍了VulDeePecker和基于深度学习的漏洞检测步骤。在VulDeePecker中,代码中用户定义的变量和函数名称被替换。VulDeePecker使用Word2vec对文本进行矢量化。为了正确比较不同分类模型的性能,本实验采用与VulDeePecker相同的预处理方法,使用第二节中提到的分类算法。漏洞检测的实验结果如表四所示。

首先,从TABLE IV中我们可以观察到,深度学习的整体效果优于传统的机器学习。与其他分类模型相比,深度学习模型的F1-score测量值平均可以提高18.78%,精度测量值平均可以提高8.41%,召回测量值平均可以提高24.71%。同时,深度学习的平均假阳性率比传统机器学习低2.32%,深度学习的平均假阴性率比传统机器学习低24.07%。这意味着,传统机器学习与深度学习的主要性能差距在于假阴性样本的数量。基于深度学习的检测模型可以检测出更多的漏洞,同时错误较少。

其次,对比深度学习模型的实验结果,我们知道BLSTM是漏洞检测的最佳算法。BLSTM模型在三个数据集上训练的F1-分数分别为88.72%、93.13%和97.79%。此外,BLSTM的其他指标也是最高的。对比传统机器学习模型的结果,我们知道,合集学习模型比简单的机器学习有更好的漏洞检测性能。RF在前两个数据集上表现最好。在CWE 119数据集上,RF的F1-score为71.59%,在CWE 399数据集上为88.23%。在CWE 664数据集上,GBDT的F1得分最高,为96.08%。

综上所述,对RQ1的回答是。(一)深度学习模型的平均F1-score比传统机器学习模型高18.78%;(二)RF在传统机器学习算法中表现最好。(三)BLSTM是漏洞检测的最佳算法。

B. RQ2:哪种矢量化方法最适合漏洞检测?

为了回答RQ2,我们研究不同向量化方法对模型性能的影响。由于深度学习模型本身使用嵌入层进行词嵌入工作,所以我们在本实验中只比较不同向量化对传统机器学习模型的影响。除了使用第二节中提到的矢量化方法,我们还评估了模型在不同数据集上的性能。值得注意的是,我们使用的是没有用户定义变量和函数替换的数据集。我们选择不做这一步,因为我们希望数据集能保留尽可能多的信息。

表五 基于机器学习的不同矢量化方法的影响

在本实验中,我们计算了不同向量化方法下机器学习模型的平均测量结果,结果如表五所示。我们观察到,CountVectorizer工具在三个数据集中都给出了最好的实验结果。使用CountVec-torizer的模型的平均F1分数为87.1%,使用其他两种向量化方法的模型的平均F1分数为66.8%和74.1%。换句话说,Countvectorizer可以使向量保留大部分的信息,这对分类是有用的。我们认为这种现象是由向量化后的处理步骤造成的。当使用矢量化方法将代码转化为矢量时,为了对齐维度,通常需要对矢量进行填充和截断。这种操作会造成信息的损失。基于索引的向量化和Word2vec都存在这个问题。但是Countvectorizer没有这个问题,因为Countvectorizer变换的向量的维度是自动对齐的,这些向量不需要调整。这可以解释为什么Countvectorizer在漏洞检测上的表现最好。

综上所述,RQ2的答案是Countvectorizer在漏洞检测上的性能最好。

C. RQ3:机器学习在执行分类任务时关注哪些特征?这些特征有什么规则吗?

人类专家使用特征来检测漏洞。这些特征通常包括一些特定的系统功能和根据经验收集的关键词。所以使用特征可以解释很多关于数据集的问题。为了分析特征,在这个实验中,我们使用RF算法来提取前100个特征,因为RF在三个数据集上都有很好的表现,并且有能力对特征进行评分。由于用户自定义变量和函数替换对数据集有影响,我们也考虑了这一点。

从数据集中提取的特征如表六所示。我们标记了所有与系统相关的特征,其中包括系统函数和代码语法关键字。研究结果可以总结为以下几点。

首先,RF算法提取的特征与人类经验定义的特征非常相似。在结果中,有很多系统函数、语法关键字、用户定义函数和用户定义变量。例如,专家经常通过系统函数来检测漏洞,因为系统函数有很多历史问题,我们的实验结果中也包含了很多系统函数,如 “malloc”、”memset “等。这些函数已经被证明是不安全的。

其次,用户自定义变量和函数替换会增加系统函数在特征中的数量。在第二节中我们提到了代码数据集中的噪声。用户自定义变量和函数替换实际上是一种降低噪声的尝试。从实验中我们观察到,这一步增加了系统相关特征的数量。但用户自定义名称的重要性被削弱了。

第三,我们发现特征提取结果与数据集来源有关。随着来自SARD的代码比例增加,系统相关特征的数量会减少。即当我们对来自NVD的代码进行特征提取时,得到更多的系统函数和关键字,当我们对来自SARD的代码进行特征提取时,得到更多的用户定义函数和名称。

综上所述,对RQ3的回答是。(i)机器学习模型重点关注的特征包括系统函数、语法关键字,这些特征与人类经验相似;(ii)用户自定义变量和函数替换可以增强系统相关特征;(iii)来自SARD的代码比例增加会导致系统相关特征减少。

表六 漏洞数据集的特征

D. RQ4:用户自定义变量和函数名称替换对漏洞检测结果有何影响?

我们在第二节介绍了用户自定义变量和函数名称替换。RQ3中的实验证明,替换可以增强系统相关的功能,所以这实际上是关于用户自定义变量和函数名称替换的影响。所以这实际上是关于用户自定义变量和函数名称替换对特征的影响。在本实验中,我们研究这种对漏洞检测性能和分类模型的影响。我们使用Word2vec进行向量化,并计算三个数据集训练的不同类型模型的平均度量。表七显示了模型在不同漏洞数据集上的分类性能,有用户自定义变量和函数名称替换和没有用户自定义变量和函数名称替换。从实验结果可以看出,没有用户定义变量和函数名称替换的模型具有更好的漏洞检测性能。这个结论适用于传统的机器学习模型和深度学习模型。

我们可以用RQ3中的结论来解释RQ4中的实验结果。TABLE VI中显示的特征包括许多系统相关的特征。然而,事实上,TABLE VI中得分最高的特征是由用户定义的函数和变量组成的。例如,我们可以在没有替换名称的数据集中找到 “badsink”、”databuffer “或 “goodg2b “等特征,而在有替换名称的数据集中找到 “var “或 “fun”。显然,特征的第一部分包含足够的信息和语义。这就是为什么用户定义的变量和函数名称替换会导致一些可用信息的损失,并增加分类模型的平均措施。来源的比例也是一个重要原因。在RQ3中,我们知道数据集中来自SARD的代码越多,我们得到的系统相关特征就越少。我们不考虑来自NVD的影响,因为来自NVD的代码是来自真实的软件。但来自SARD的代码是用来重现漏洞的,代码中的变量名和函数名会包含很多信息。这样的代码可以帮助开发者理解漏洞的原理,为机器学习提供更有规律的特征。因此,信息的丢失与数据集的来源密切相关。

表七 分类模型在漏洞检测上的表现

综上所述,对RQ4的回答是,没有用户自定义变量和函数名称替换的模型具有更好的漏洞检测性能。

E. 对有效性的威胁

在本文中,本实验的有效性可能存在两种威胁。一方面,统计偏差是内部有效性的主要威胁。由于数据集规模大,实验中需要控制的因素多,很容易造成实验结果的意外。为了缓解这种潜在的威胁,我们采用了随机洗牌数据集并重复迭代运行的方法。这样可以保证机器学习模型的结果能够收敛到稳定的数值。另一方面,数据集本身也会威胁到外部有效性。除了保证数据集的来源可靠外,我们还应该保证数据标签的正确性。本文在[9]的基础上收集了NVD和SARD的数据集,我们使用了一种新的标签方法对SARD的数据进行标签。这一步降低了误标的概率。

 

第五节 相关工作

以往与基于机器学习的漏洞检测相关的研究可以分为基于传统机器学习的检测和基于深度学习的检测。以往关于基于机器学习的传统漏洞检测的研究包括[20]-[21][22][23][24][25][26][27][28][29][30][31]。以往基于深度学习的漏洞检测研究主要包括[9]、[27]、[32]、[33]。也有一些研究,分析了漏洞检测的影响因素。Shabtai等人[32],[34]-[35][36]对该课题的相关因素进行了整理,其中包含分类算法、特征提取和不平衡问题。Kawaguchi等[22],[37]结合动态分析研究了漏洞检测的因素。

我们进行对比研究,评估不同因素的影响。但是,Shabtai等[32],[34]-[35][36]等大部分调查都没有提到漏洞检测的向量化方法和用户自定义变量和函数名称替换。因此,我们的研究是对本课题其他研究的补充,我们的研究结果可以为更好地使用我们研究的漏洞检测框架提供指导。

 

第六节 结论与未来工作

在本文中,我们研究了基于机器学习的漏洞检测的因素。我们研究的主要结论包括 (一)深度学习模型比机器学习有更好的分类效果,BLSTM是漏洞检测的最佳模型。(二)使用CountVectorizer可以提高机器学习模型的实验结果。(三)从代码数据集中提取的特征与人的经验相似,会受到源比例和预处理方法的影响。(四)用户自定义变量和函数名称替换提高了系统相关特征的数量,但对漏洞检测没有帮助。

但在实验中,我们仍有改进的空间。首先,我们只关注三类漏洞。未来的研究需要更多的漏洞和更多的数据集。第二,从实验结果中我们发现,NVD和SARD的代码呈现出不同的特点。在未来,我们将分析NVD和SARD对漏洞检测的具体影响。此外,我们还将研究其他先进的建模方法[38]、[39]和数据预处理方法[40]、[41]。

 

引用

1.M. S. Abdullah A. Zainal M. A. Maarof and M. Nizam Kassim “Cyber-attack features for detecting cyber threat incidents from online news” 2018 Cyber Resilience Conference (CRC) pp. 1-4 Nov 2018.

下略

(完)