安全漏洞是引发网络空间安全事件的根源,软件系统作为网络空间的一个重要组成部分,其安全缺陷严重威胁了网络空间安全。软件系统由富有语义信息的源代码构成,因此,在软件开发生命周期的各个阶段进行源代码安全审计有利于及早发现并修复缺陷。由于对专家经验和人工参与的过度依赖,即使资深的分析人员也需经过长时间分析才可能发现1个较高价值的缺陷。随着深度学习、数据挖掘等技术在恶意代码分析、垃圾邮件分类、入侵检测等方面的取得成功,学术界开始尝试将深度学习用于源代码安全审计[1-4],旨在自动化地发现并修复源代码缺陷,保障软件系统安全运行。本文提出基于文本卷积神经网络(text convolution neural network,TextCNN)的多类源代码缺陷检测方法,旨在利用TextCNN学习源代码数据流中蕴含的深层次语义特征,训练形成源代码缺陷检测卷积网络,实现跨函数的多类源代码缺陷检测。
1 相关工作基于深度学习的方法认为源代码本质上属于文本信息,在不依赖专家知识的前提下,深度学习算法能够自动挖掘源代码中的语义信息和逻辑关系获得缺陷代码的模式,并训练形成相应的分类模型,实现源代码缺陷检测。Russell等[5]针对C/C++开源软件代码,提出了基于深度学习的函数级缺陷检测方法,直接以函数体作为分析最小单位,能够判定目标函数是否存在缺陷,不适用于包含跨函数数据依赖关系的代码缺陷检测。Li等[6-7]采用深度学习的方式,实现了基于程序数据流提取的源代码切片缺陷检测。该方法仅采用单一的词向量作为代码表征方法,基于双向LSTM实现了源代码缺陷的二分类检测,并未在多特征融合、多分类等方面做进一步研究;Zhou等[8]实现了基于图神经网络的源代码缺陷检测系统Devign,同样是一个二分类源代码缺陷检测方法,即给定源代码数据判断其是否为缺陷,无法判断源代码缺陷类型。Harer等[9]针对C/C++源代码,采用机器学习方法进行数据驱动的缺陷检测,并比较了应用到源代码和编译后代码的效果,该方法的不足在于要求待测代码必须完成编译,而在实际生产过程中,代码编译环境配置将消耗大量时间,严重制约了分析效率。Duan等[10]实现了基于注意力机制的源代码缺陷检测方法VulSniper,实现了多类的源代码缺陷检测,但涉及的源代码缺陷类别较少,只涉及了CWE119和CWE399两类缺陷。
现有的方法主要存在3个问题:1) 由于基于深度学习的方法对先验知识要求高,而涵盖各类缺陷的大规模标记数据集的缺乏,现有的工作往往过分依赖人为刻意制造的、较简单的缺陷数据集,例如美国国家标准与技术研究院维护的软件保障参考数据集(software assurance reference dataset,SARD)。2) 预处理及代码表征过程中通常仅采用1种词嵌套方式生成深度学习模型的输入,而未考虑将多种词嵌套方式结合生成的数据用作源代码缺陷检测深度学习模型的输入。3) 基于深度学习的源代码缺陷检测研究中,多为二分类工作,对于源代码缺陷检测的多分类研究较少。
2 方法介绍本文将文本卷积神经网络应用到源代码缺陷检测,方法适用于源代码片段、文件以及项目工程级别的源代码数据。本文的整体架构如图 1所示,主要包含预处理、代码表征和TextCNN模型3部分,以解决问题1和问题2。
2.1 数据预处理
TextCNN在文本分类领域发挥作用,关键在于能够学习文本间的逻辑关系。源代码本质上是文本信息,其逻辑关系、词性等特征是通过数据流关系体现,本文方法基于数据流,构建函数内、函数间的数据依赖关系。
数据流分析试图确定在程序的某一节点,各个变量的使用或者可能取值情况。数据流分析主要有前向分析(forward analysis)和后向分析(backward analysis)两种方法。Fortify、Checkmarx等多款源代码缺陷检测软件引入了数据流分析技术。本文采用开源工具joern在语法分析、词法分析基础上提取了代码的抽象语法树、数据流信息作为依据,构建跨函数的代码切片。例如,以strcpy()作为分析规则,进行反向数据流分析,获得与strcpy()及其变量(buf, str) 相关的数据依赖关系,实现了变量buf、str的跨函数数据流分析,生成较为完整的上下文关系,数据生成如图 2所示。根据SARD和开源软件代码可生成大量的富有数据依赖关系的代码切片数据,以增强数据集的实用性,支持多类源代码缺陷检测。基于数据集中的跨函数数据流切片训练形成的深度学习模型可支持跨函数的源代码缺陷检测,以解决问题1。
2.2 样本数据表征
自然语言处理领域对于文本分析任务,首先将文本表示为向量形式,常用的方法有独热编码、词嵌套等。独热编码产生的词向量是高维稀疏的二值向量,对于上下文语义关系表示不充分。词嵌套技术生成的是低维稠密的词向量,两个词向量的距离能够度量词的相似性,并且词向量求和与词的语义关系相匹配。例如,采用word2vec[11]生成的“番茄”—“西红柿”与“菜花”—“花菜”词向量十分相似。因此,本文选择词嵌套方式,为了探索不同词嵌套方式的检测效果,采用word2vec、fasttex[12]及其融合结果表征源代码样本数据。
本文中x表示一个代码单元(一个代码或者一行代码),其中在给定的代码片段X是代码单元的集合,包含n个代码单元:
$ X = \{ {x^1}, {x^2}, \ldots , {x^n}\} . $ | (1) |
每个代码单元可以表示为d维向量v,则代码片段S可以用矩阵Mn·d表示如下:
$ {\mathit{\boldsymbol{M}}^{n·d}} = {[{\mathit{\boldsymbol{v}}^1}, {\mathit{\boldsymbol{v}}^2}, \ldots , {\mathit{\boldsymbol{v}}^n}]^{\rm{T}}}. $ | (2) |
Vocab表示所有代码单元的向量表达构成的集合,并包含每个代码单元的多种表示形式。本文中采用的是word2vec和fasttext,所形成的的集合分别为Vw、Vf。测试代码中的代码单元i的向量表达可以通过函数Lookup从Vocab中获得word2vec和fasttext对应的词向量表达Vwi和Vfi,Vi表示word2vec与fasttext的向量的特征融合结果,本文采用concatenate方式将word2vec与fasttext结果进行联结,实现了两种词嵌套特征的融合,以解决问题2。
$ \mathit{\boldsymbol{V}}_{\rm{w}}^i = {\rm{Lookup}}(i, {\rm{Voca}}{{\rm{b}}_{\rm{w}}}). $ | (3) |
$ \mathit{\boldsymbol{V}}_{\rm{f}}^i = {\rm{Lookup}}(i, {\rm{Voca}}{{\rm{b}}_{\rm{f}}}). $ | (4) |
$ {\mathit{\boldsymbol{V}}^i} = {\rm{concatenate}}(\mathit{\boldsymbol{V}}_{\rm{w}}^i, \mathit{\boldsymbol{V}}_{\rm{f}}^i). $ | (5) |
受检代码片段Xj中含有l个代码单元,X将映射为一个l·d的矩阵:
$ {\mathit{\boldsymbol{M}}^{j, n·d}} = {[{\mathit{\boldsymbol{v}}^1}, {\mathit{\boldsymbol{v}}^2}, \ldots , {\mathit{\boldsymbol{v}}^l}]^{\rm{T}}}. $ | (6) |
本文模型基于Kim等[13]提出的TextCNN模型,TextCNN可以使用独热编码、词嵌套等多种数据作为输入。为了充分保留代码的上下文语义信息,本文采用word2vec、fasttext预训练形成的向量构建代码向量Matrix(X)作为TextCNN的输入。卷积层、池化层等沿用Kim提出的网络模型,TextCNN的网络结构如图 3所示。
在模型的第一层,每个样本映射为n·d维矩阵M,假设待测样本数量为L,那么所有样本S可以表示为
$ {\mathit{\boldsymbol{M}}^{1, L}} = {[{\mathit{\boldsymbol{M}}^1}, {\mathit{\boldsymbol{M}}^2}, \ldots , {\mathit{\boldsymbol{M}}^L}]^{\rm{T}}}. $ | (7) |
TextCNN最后一层使用softmax激活函数计算样本X所属类别的概率。假设所有样本可以分为K(K=0,1,2,…, k,k=K-1)类,每个样本的预测标签为k的概率可以表示为:
$ p\left( {y = k|X} \right) = \frac{{{\rm{exp}}(w_k^{\rm{T}}x + {b_k})}}{{\sum\limits_{k' = 0}^k {{\rm{exp}}} (w_{k' }^{\rm{T}}x + {b_{k' }})}}. $ | (8) |
其中:wk表示训练的权重,bk表示偏置。
3 实验与评估 3.1 实验环境实验所用的计算机使用CPU为2颗E5-2683-v4,主频为2.1 GHz,显卡为2块titan Xp,硬盘容量为2 T,内存大小是256 G。软件环境采用Linux 18.04 x64,开发语言Python3.7,模型编写采用keras,后端内核为tensorflow。
3.2 实验数据集实验所用数据集包括SARD和真实代码。SARD覆盖了C、C ++、Java、PHP和C#等编程语言共计170 000多个程序,涵盖了150多个类别缺陷。每种缺陷类型包含大量测试用例,测试用例被标记为“good”“bad”或“mixed”。“bad”测试案例包含一个或多个特定的缺陷。“good”测试用例是“bad”测试用例的修复版本,可以用来检查误报。“mixed”测试用例同时具有缺陷的代码和对应的修复后的代码。此外,在实验数据集中加入实际项目的代码,根据项目的历史缺陷和源代码缺陷检测工具checkmarx、fortify等的扫描结果,提取项目源代码的切片信息,并进行标注,所有测试用例根据CWEID进行标注。
本文仅涉及C、C++源代码的缺陷,共计60类,如表 1所示。其中,正样本数量173 221,负样本数量147 470。
名称 | 缺陷编号 | |||||
缺陷类型 | CWE415 | CWE398 | CWE190 | CWE79 | CWE646 | CWE352 |
CWE170 | CWE182 | CWE732 | CWE377 | CWE829 | CWE134 | |
CWE330 | CWE122 | CWE457 | CWE259 | CWE426 | CWE326 | |
CWE36 | CWE522 | CWE208 | CWE350 | CWE131 | CWE416 | |
CWE497 | CWE99 | CWE203 | CWE477 | CWE252 | CWE566 | |
CWE129 | CWE242 | CWE759 | CWE404 | CWE113 | CWE193 | |
CWE615 | CWE121 | CWE244 | CWE209 | CWE674 | CWE285 | |
CWE1022 | CWE467 | CWE319 | CWE590 | CWE401 | CWE120 | |
CWE476 | CWE369 | CWE411 | CWE547 | CWE89 | CWE248 | |
CWE562 | CWE256 | CWE321 | CWE681 | CWE693 | CWE601 |
3.3 实验参数设置
参数设置主要包含word2vec、fasttext和TextCNN 3部分。
Word2vec和fasttext模型利用开源工具包gensim进行训练,训练过程中利用多线程并行提升训练速度。将每个代码单元训练为d=30的向量,滑动词窗大小为5,学习率为0.01,采样率为0.01,迭代次数为5。
TextCNN的输入样本为代码片段,每个代码片段由若干代码单元构成。所有代码片段填充为长度为L的向量。L的取值为含有代码单元最多的代码片段的长度,L=802。卷积层步长为2,卷积核尺寸分别为3、4、5,激活函数采用relu。池化层采用maxpooling,池化尺度为2,下采样率Dropout=0.3,损失函数为categoricalcrossentropy,表示如下:
$ {\rm{loss}} = - \sum\limits_{i = 1}^n {{{\hat y}_{i1}}} {\rm{log}}{y_{i1}} + {\hat y_{i2}}{\rm{log}}{\mathit{y}_{i2}} + \cdots + {\hat y_{im}}{\rm{log}}{y_{im}}. $ | (9) |
最终,输出层采用激活函数softmax。在多类源代码缺陷数据的支持下,基于TextCNN实现多分类源代码缺陷检测,以解决问题3。
3.4 评估参数在机器学习领域,混淆矩阵是一个通用的应用指标,有助于理解分类器的性能。该矩阵描述了实际类别和预测类别之间的混合,即真阳性(true positive, TP)、假阴性(false negative, FN)、假阳性(false positive, FP)和真阴性(true negative, TN)。TP表示缺陷代码功能被分类为缺陷代码的情况,FN表示缺陷代码被分类为正常代码的情况,FP表示正常代码被分类缺陷代码的情况。TN表示正常代码被分类正常代码的情况。基于上述介绍,本文使用3种评估指标:召回率(recall)、精确度(precision)和F1。
$ {\rm{recall = }}\frac{{{\rm{TP}}}}{{{\rm{TP + FN}}}}{\rm{ \times 100\% }}, $ | (10) |
$ {\rm{precision = }}\frac{{{\rm{TP}}}}{{{\rm{TP + FP}}}}{\rm{ \times 100\% }}, $ | (11) |
$ {F_1} = \frac{{2 \times \left( {{\rm{recall·precision}}} \right)}}{{{\rm{recall + precision}}}} \times 100\% . $ | (12) |
为了验证本文方法的有效性,将本文方法与现有的基于学习的方法从上述评估参数的3个维度进行了对比分析,结果如表 2所示。
通过与其他基于深度学习的源代码缺陷检测方法对比,本文方法有以下优势:
1) 在支持缺陷类型方面,适用的缺陷类别数量更多,Vuldeepecker为2分类,SySeVr适用分类数量为40类,本文方法适用缺陷类型为60类。
2) 采用特征融合的方式在精确度较Vuldeepecker、SySeVr分别提升了3.4%、11.1%;召回率较Vuldeepecker提升34.2%;F1较Vuldeepecker、SySeVr分别提升24.5%、3.7%。
3) 本文词嵌套向量d=30,Vuldeepecker、SySeVr的词嵌套向量均大于200,本文方法节省了较多的计算资源,提升了模型的学习效率。
4 结论本文将静态分析技术与深度学习技术相结合,使用TextCNN自动化的学习源代码中潜在的缺陷模式,实现了跨函数的代码缺陷检测方法,有效缓解了对专家经验、编译环境的高度依赖。通过公开数据集SARD验证,表明本文方法是有效的。在评估参数方面,平均精确度达95.3%,召回率为84.7%,F1评估参数为89.7%,检测的源代码缺陷种类为60类,整体效果优于现有的基于深度学习的源代码缺陷检测方法。采用开源项目openssl进行验证,能够检测出heardbleed缺陷代码,说明本文方法在实际代码的缺陷检测中是有效的。
本文实现了基于多特征融合的深度卷积神经网络源代码缺陷检测方法和支持跨函数的多分类源代码缺陷检测方法;构建了较SARD更贴近实际代码的源代码缺陷检测数据集。不足在于仅考虑利用数据流表征代码的上下文信息,未来工作可以扩展代码上下文表征方式,将软件度量元信息、文本的统计信息等加以考虑,利用深度学习方法挖掘出更加丰富的源代码语义信息。
[1] |
邹权臣, 张涛, 吴润浦, 等. 从自动化到智能化: 软件漏洞挖掘技术进展[J]. 清华大学学报(自然科学版), 2018, 58(12): 1079-1094. ZOU Q C, ZHANG T, WU R P, et al. From automation to intelligence: Survey of research on vulnerability discovery techniques[J]. Journal of Tsinghua University (Science & Technology), 2018, 58(12): 1079-1094. (in Chinese) |
[2] |
贾凡, 孔令智. 基于卷积神经网络的入侵检测算法[J]. 北京理工大学学报, 2017, 37(12): 1271-1275. JIA F, KONG L Z. Intrusion detection algorithm based on convolutional neural network[J]. Transactions of Beijing Institute of Technology, 2017, 37(12): 1271-1275. (in Chinese) |
[3] |
BIAN P, LIANG B, ZHANG Y, et al. Detecting bugs by discovering expectations and their violations[J]. IEEE Transactions on Software Engineering, 2018, 45(10): 984-1001. |
[4] |
WANG S, LIU T Y, TAN L. Automatically learning semantic features for defect prediction[C]//Proceedings of 2016 IEEE/ACM 38th International Conference on Software Engineering. Austin, USA: IEEE, 2016: 297-308.
|
[5] |
RUSSELL R, KIM L, HAMILTON L, et al. Automated vulnerability detection in source code using deep representation learning[C]//Proceedings of the 17th IEEE International Conference on Machine Learning and Applications. Orlando, USA: IEEE, 2018: 757-762.
|
[6] |
LI Z, ZOU D Q, XU H, et al. VulDeePecker: A deep learning-based system for vulnerability detection[C]//Proceedings of the Network and Distributed Systems Security Symposium. San Diego, USA: ISOC, 2018.
|
[7] |
LI Z, ZOU D Q, XU S H, et al. SySeVR: A framework for using deep learning to detect software vulnerabilities[J]. arXiv preprint arXiv: 1807.06756, 2018.
|
[8] |
ZHOU Y Q, LIU S Q, SIOW J, et al. Devign: Effective vulnerability identification by learning comprehensive program semantics via graph neural networks[C]//Proceedings of the 33rd Conference on Neural Information Processing Systems (NeurIPS 2019). Vancouver, Canada, 2019: 10197-10207.
|
[9] |
HARER J A, KIM L Y, RUSSELL R L, et al. Automated software vulnerability detection with machine learning[J]. arXiv preprint arXiv: 1803.04497, 2018
|
[10] |
DUAN X, WU J Z, JI S L, et al. VulSniper: Focus your attention to shoot fine-grained vulnerabilities[C]//Proceedings of the 28th International Joint Conference on Artificial Intelligence. Macoa, China, 2019: 4665-4671.
|
[11] |
MIKOLOV T, SUTSKEVER I, CHEN K, et al. Distributed representations of words and phrases and their compositionality[C]//Proceedings of the 26th International Conference on Neural Information Processing Systems. Lake Tahoe, Nevada: Curran Associates Inc., 2013: 3111-3119.
|
[12] |
JOULIN A, GRAVE E, BOJANOWSKI P, et al. Bag of tricks for efficient text classification[C]//Proceedings of the 15th Conference of the European Chapter of the Association for Computational Linguistics: Volume 2. Valencia, Spain: Association for Computational Linguistics, 2017: 427-431.
|
[13] |
KIM Y. Convolutional neural networks for sentence classification[C]//Proceedings of the 2014 Conference on Empirical Methods in Natural Language Processing. Doha, Qatar: Association for Computational Linguistics, 2014: 10.3115/v1/D14-1181.
|