当前, 有一些机构或组织对软件开发中发现的缺陷进行了收集、整理与发布, 因此通过该类缺陷库即可获得缺陷条目入口. 但是该类缺陷库大多只有部分条目能够链接到缺陷对应的源代码, 因此基于缺陷库抽取缺陷数据的方法大多需要先筛选出其中对齐源代码成功的条目, 再进行后续的处理.
NVD (national vulnerability database)[40]是美国国土安全部下属的联邦计算机应急准备小组维护的国家漏洞数据库, 是当前较为权威的源代码漏洞数据库. 该库实时同步CVE发布的条目, 在CVE基础上提供安全评分、缺陷影响评级、修复信息、缺陷查找等功能, 并通过人工审核的方式将缺陷与原项目相关信息进行链接.由于其数据相对较为齐全, 人工对齐源码出处的质量相对较高, 因此该缺陷库成为当前最常用的缺陷抽取源.
Lin等人[41]使用函数作为缺陷代码的粒度, 其选择了6个知名工程(LibTIFF、LibPNG、FFmpeg、Pidgin、VLC Media Player、Asterisk), 通过NVD检索其相关缺陷, 并人工定位缺陷所在函数, 剩余未被标记为缺陷函数的即作为非缺陷函数加入数据集. 最终, 该数据集包含32 988个函数, 其中, 缺陷函数为457个, 占比1.4%, 不平衡的情况较严重. 该数据集已开源(https://github.com/DanielLin1986/TransferRepresentationLearning).
Li等人[42]提出了基于C/C++语言的切片级缺陷代码数据集. 其检索了NVD与Sard中缓冲区错误(CWE-119)与资源管理错误(CWE-399)这两类缺陷条目, 选择其中19个开源C/C++项目的相关缺陷. 其定义了代码片段(code gadgets), 即语义上相互关联的几行代码, 并用它来表示程序, 以使其避免函数级表示会带来的无关噪声信息. 其首先在源代码中按照分析工具Checkmarx的危险函数标准查找库函数与API函数调用作为危险入口, 将其语句中的变量作为起点进行切片, 并按照自然代码顺序进行组合形成code gadget. 该切片只考虑数据依赖关系. 在标注是否含有缺陷时, 其依靠代码片段中是否含有修复时被删除或修改的语句来进行判断: 若有, 则标注为缺陷片段. 最终, 该数据集包含61 638个代码片段, 其中, 17 725个为缺陷片段, 占比28.8%. 不过, 其中仅有1.4% (840个)来自于真实项目缺陷(NVD). 该数据集已开源(https://github.com/CGCL-codes/VulDeePecker).
为了支持多分类缺陷检测任务, Zou等人[43]在VulDeePecker[42]数据集上进行了扩充, 增加了控制依赖作为切片依据, 并将缺陷类型也加入其中, 而不仅仅记录其是否含有缺陷. 其μVulDeePecker数据集在切片时同时进行前后向的切片, 并同时考虑数据依赖与控制依赖. 该数据集最终包含181 641个代码片段, 其中, 43 119个为缺陷片段, 占比23.7%. 其共涉及40个CWE三级分类. 但是, 该数据集的缺陷样本存在类型信息, 而非缺陷样本均标记为非缺陷类型, 不存在类型信息, 可能会影响模型的判断. 并且, 该数据集中来自NVD的真实缺陷占比不到1%. 该数据集已开源(https://github.com/muVulDeePecker/muVulDeePecker).
由于VulDeePecker[42]数据集只考虑了以危险库/API函数调用作为入口的缺陷条目作为样本, 因此只能提供两种缺陷类型的样本, 其覆盖范围较窄. Li等人[44]在其基础上进行了改进, 使其同时兼顾语法特征与语义特征, 从而更全面地表征缺陷以覆盖更多的缺陷类型. 该数据集SySeVR同样从NVD与Sard数据库中抽取缺陷, 其首先根据Checkmarx的危险变量规则提出了4种危险入口(库/API函数调用、数组使用、指针使用、算数表达式), 从代码中的危险入口开始切片. 与VulDeePecker数据集根据语句中的标识符进行切片不同的是, SySeVR数据集是在语句的程序依赖图基础上进行切片, 从而利用控制依赖与数据依赖信息完善缺陷特征. SySeVR的标签方法与VulDeePecker数据集相同. 最终, SySeVR数据集包含420 627个代码片段, 其中, 缺陷片段为56 395个, 占比13.4%. 该数据集已开源(https://github.com/SySeVR/SySeVR).
缺陷代码与其修复版本同时在数据集中可以帮助模型更好地学习到其中的差异, 并且能够保证数据集正负样本的平衡. 为此, Xiao等人[45]构建了一个针对C/C++的缺陷代码与修复数据集. 其选定了10个不同领域的开源工程, 从NVD和项目代码提交中检索相关缺陷与修复, 根据修复的位置确定缺陷函数. 该数据集只包含修复在单个函数内部的. 最终, 该数据集包含25 377对缺陷与其修复. 不过, 该数据集未开源.
Nikitopoulos等人[46]构建了一个多语言的缺陷代码数据集CrossVul. 其人工审查了NVD提及的5 877个Github提交, 确认其链接的可用性, 并标记了缺陷及其对应补丁所在文件, 并将提交信息也作为数据一同保存. 该数据集最终涉及1 675个项目, 包括27 476个文件(缺陷与非缺陷各半), 涵盖40种编程语言, 涉及168个CWE类型, 每一条缺陷都记录了其对应的CVE ID与其来源链接. 不过, 该数据集只是文件级数据, 并没有进一步细化到函数甚至切片, 因此, 在缺陷检测任务中使用可能需要较大工作量的细化标注工作. 该数据集已开源(https://doi.org/10.5281/zenodo.4734050).
Lin等人[47]提出了一个针对深度学习缺陷函数检测的C语言评测集. 其根据NVD与CVE的描述信息, 通过人工的方式将其对齐到GitHub代码库, 并标注缺陷函数与缺陷文件. 其默认最新版本的工程中其他文件均为非缺陷文件, 因此将新版本中未被标记的文件和其中函数作为非缺陷样本. 其标注了9个开源工程, 共计5 780个文件60 768个函数, 其中, 缺陷函数为1 471个, 占比2.4%. 但是, 该数据集没有考虑到缺陷类型等信息.
为了测试跨域学习方法的效果, Liu等人[48]提出了一个针对C/C++的缺陷代码数据集. 其选用了VulDeePecker数据集中的CWE-119与CWE-399这两类, 用来测试缺陷类型间的跨域. 其另外根据NVD与CVE信息人工标注了3个开源项目(LibTIFF、FFmpeg、LibPNG)的函数级缺陷数据, 每个项目均抽取了9种缺陷类型, 用来测试项目间的跨域. 非缺陷样本都是从项目中未被标记为缺陷样本的函数中抽取的. 该数据集已开源(https://github.com/wolong3385/SVD-Source).
很多缺陷代码数据集在构造时都基于一个假设: 工程代码除了已知的缺陷以外没有其他缺陷. 因此, 设计者将被标记为缺陷样本以外的部分当作非缺陷样本对待. 然而事实是, 新缺陷都是从这些“非缺陷样本”中发现的. 因此, 这种假设会带来许多噪声从而影响模型的判别能力.
为此, Jimenez等人[49]放弃了缺陷样本以外的代码来避免这个问题, 他们只使用缺陷样本和其对应的修改后版本作为样本来构造数据集. 他们提出了一个自动的可扩展框架, 并由此构建了缺陷代码数据集VulData7. 其通过NVD作为缺陷入口, 选取4个C语言开源项目(Linux Kernel、Wireshark、OpenSSL、SystemD)的条目, 自动将其对齐到项目代码库及相应提交. VulData7记录了每条缺陷的报告信息(描述、CVE编号、CWE编号、CVSS严重程度)、影响版本列表、修复提交和修复前后文件. 当前版本的VulData7包含2 809条缺陷, 其中, 1 598条附带了修复信息. 其更新机制会不断同步NVD以不断维护数据集. 该数据集已开源(https://github.com/electricalwind/data7).
Clemente等人[50]从缺陷跟踪网站Bugzilla、Mozilla Foundation Security Advisory (MFSA)和Computer Vulnerability Exposure site (CVE)上提取信息构建缺陷数据集. 其将搜索范围限定在Mozilla的C++项目Firefox上, 根据网站的报出提取出缺陷相关文件. 最终, 该数据集包含395个文件, 其中有200个缺陷样本, 占比50.6%. 该数据集未开源.
除了著名的通用缺陷库以外, 许多大型软件开发商都会安排安全团队自行维护其软件产品的安全记录, 这些安全记录也可以为构建缺陷代码数据集提供可靠的信息.
Alexopoulos等人[51]提出了一种自动构建缺陷数据集的方法. 他们从Debian安全团队维护的缺陷库Debian Security Advisories (DSAs)中进行信息挖掘. 首先, 从DSA的缺陷报告中可以直接提取出报出的缺陷与对应的NVD链接, 同时还包括其CWE缺陷类型与严重等级; 随后, 使用官方提供的快照功能下载每个月的工程源代码; 再通过开源工具PKGDIFF对相邻版本的修改信息进行生成, 从而定位出缺陷报告是在何时被引入. 该数据集最终选用了7个Debian项目, 分别是Linux kernel、Firefox、Chromium、PHP、OpenJDK、Thunderbird和Wireshark. 不过, 由于该研究还未完全完成, 该数据集未开源.
Fan等人[52]提出了一个针对C/C++语言的函数级缺陷代码数据集Big-Vul. 其通过爬取CVE数据库和相关源代码仓库中的GitHub链接, 定位了348个GitHub项目, 并对齐到每个缺陷的修复提交. 其将函数在修复前后两个版本与CVE描述信息一并保存, 记录了包括CVE ID、严重程度、描述等21个特征值. 项目中的其他非缺陷相关函数作为正确函数也加以保留. 最终, Big-Vul数据集包含3 754个代码缺陷, 覆盖91个缺陷类型, 共含有11 823个缺陷函数与253 096个非缺陷函数, 缺陷函数占比4.5%. 该数据集已开源(https://github.com/ZeoVan/MSR_20_Code_Vulnerability_CSV_Dataset).
Li等人[53]从tera-PROMISE缺陷数据库中抽取针对Java语言的文件级缺陷代码数据集. 其选择了7个开源Java项目包含的缺陷条目, 每个项目都选择了连续的两个版本. 从其对应的GitHub仓库中爬取了源文件, 并按照报出缺陷位置对文件进行标注. 最终, 该数据集包含3 290个文件, 其中, 缺陷文件为1 152个, 占比35%. 该数据集未开源.
Zhang等人[54]同样从tera-PROMISE数据集中抽取缺陷数据, 其选择了12个Java语言的开源项目, 共计5 194个文件, 其中, 缺陷文件为1 617个, 占比31.1%. 该数据集同时还包含了20种传统代码度量信息.
Ponta等人[55]将NVD和50余个项目自身的安全记录网站作为缺陷条目入口, 在4年的时间内监控其安全报告的情况, 通过人工的方式记录缺陷相关提交(commit)与修复相关提交. 截至2019年, 该数据集共记录了624个缺陷的修复, 涉及1 282个提交, 跨越205个Java项目. 该数据集已开源(https://github.com/SAP/vulnerability-assessment-kb/tree/master/MSR2019).
当前, 从NVD等缺陷库中抽取缺陷条目已成为较为通用的做法, 其已经成为构建缺陷代码数据集的重要数据来源. 这就意味着源缺陷库的质量会极大地影响所构建数据集的质量. 事实上, 通过细致的比对, 人们逐渐注意到该类缺陷库的信息质量存在一些问题. 例如, 在多个缺陷来源的对比中(如NVD与CVE)会出现缺陷信息不一致的情况. 如果对缺陷库中的条目不加验证即作为标答(当今普遍做法), 会给缺陷数据集的构建带来噪声, 继而极大地影响在此基础上训练的深度学习模型的检测性能. 为此, Dong等人[56]提出了一个自动化系统VIEM来检测完全标准化的NVD数据库与非结构化CVE描述及其引用的漏洞报告之间的不一致信息.其使用了自然语言处理任务中的命名实体识别与关系抽取技术, 对非结构化信息进行提取并与结构化信息比较, 从而大规模地自动检测不一致信息. 其对过去20年中78 296个CVE ID与70 569条缺陷报告进行了比对, 只有59.82%的条目可以严格匹配.
然而, 该不一致性的鉴别只针对缺陷影响的项目版本不一致性. 事实上, 由于公开缺陷库都是由人工的方式进行维护, 其许多信息都可能存在错误/不一致, 例如对应的原提交链接等. 这些都会给以此为基础构造的缺陷代码数据集带来影响, 也需要进行正确性的确认.
除了数据的冲突, 另一种影响数据集数量的问题是数据的缺失. 当前, 由于需要大量的缺陷代码数据, 使用混合数据来源已成为一种常用的扩增数据集的做法. 但是, 混合数据来源容易带来的问题是属性值的不全, 这是由各个缺陷库的数据存储结构所导致的. 即使是同一数据源的缺陷数据, 也可能有数据不全的情况. 例如, 在NVD缺陷库中, 有些条目没有CVE缺陷类型. 这种数据的缺失会影响数据集的数量与质量, 需要对其进行补全.
Rostami等人[57]针对缺陷代码数据中数据缺失的问题设计了一个机器学习框架, 从数据完整的条目中学习, 从而对缺失项进行预测. 该方法能够较好地预测缺失的类型数据, 但对于无类型数据, 该框架无法补全.
Gonzalez等人[58]同样针对NVD数据集中分类信息补全标注的问题, 提出了一个自动缺陷标注的方法. 其仅仅使用缺陷条目的CVE描述作为依据, 在对描述信息进行清洗并使用TF-IDF表示后, 使用6种分类器(朴素贝叶斯、决策树、支持向量机、随机森林、AdaBoost支持向量机、多数投票), 按照NVD漏洞描述规则(vulnerability description ontology)中的19个类型标准来对其进行分类. 实验结果显示: 多数投票的分类效果最佳, 准确率达到74.5%. 但考虑到训练成本和时间, 使用支持向量机是该任务的最优选择. 不过, 该方法同样无法对选择型数据进行补全.
因此, 对于非选择型数据的缺失, 如何对其加以补全而不是简单丢弃, 是构造一个样本数量足够多的数据集的可行方向, 一些生成式的方法值得探究.
总的来说, 基于缺陷库抽取的方法利用了现有的人工审查后的缺陷资源, 因此在缺陷来源上可靠性较高.使用该类方法构造的缺陷代码数据集, 其主要针对的是具有CVE编码的真实软件缺陷, 可以认为其样本较为贴近缺陷检测理想的使用场景. 但是, 由于缺陷库需要相关人员的审查, 因此即使经过数十年的积累(如NVD), 现有的缺陷库中可被用于抽取样本的缺陷条目数量仍然极为有限.