基于异构图表征的源代码漏洞检测方法
Source code vulnerability detection method based on heterogeneous graph representation
收稿日期: 2024-08-21
基金资助: |
|
Received: 2024-08-21
Fund supported: | 国家自然科学基金资助项目(61762058,62461032);甘肃省教育厅产业支撑项目(2022CYZC-38);甘肃省重点研发计划资助项目(25YEFA089);国家电网科技资助项目(W32KJ2722010,522722220013). |
作者简介 About authors
张学军(1977—),男,教授,博导,从事网络安全、数据隐私与机器学习的研究.orcid.org/0000-0002-0350-359X.E-mail:
针对现有的源代码漏洞检测模型对异构特征和底层信息提取不足导致的检测准确率不高的问题,提出基于异构图表征的源代码漏洞检测方法. 从中间代码表示(IR)中提取8种指令级特征作为程序依赖图的节点嵌入,解决底层信息提取不足的问题. 在节点层和依赖层分别构建基于注意力机制的聚合模块来提取图表征数据中的异构性特征,通过调整注意力系数捕获关键节点信息. 对图数据的聚合结果进行分类,预测是否存在漏洞. 在合成数据集和2个真实项目数据集上的实验表明,相比于现有方法,本文方法具有更强的异构特征提取能力和更高的漏洞检测综合性能.
关键词:
A source code vulnerability detection method based on heterogeneous graph representation was proposed aiming at the problem of low detection accuracy caused by the insufficient extraction of heterogeneous features and low-level information in the existing source code vulnerability detection models. Eight instruction-level features were extracted from the intermediate code representation (IR) to serve as node embeddings for the program dependence graph, which addressed the issue of missing low-level information. Attention aggregation mechanisms were constructed at the node level and dependency level respectively to extract heterogeneous features, and information of key nodes was extracted by adjusting attention coefficients. The aggregated results of the graph data were classified to predict the presence of vulnerability. The experiments on synthetic data sets and two real project data sets show that the proposed method has stronger capabilities in extracting heterogeneous features and higher comprehensive performance in vulnerability detection compared with existing methods.
Keywords:
本文引用格式
张学军, 梁书滨, 白万荣, 张奉鹤, 黄海燕, 郭梅凤, 陈卓.
ZHANG Xuejun, LIANG Shubin, BAI Wanrong, ZHANG Fenghe, HUANG Haiyan, GUO Meifeng, CHEN Zhuo.
随着市场对软件安全需求的提升,针对软件漏洞的检测成为该领域的研究热点[1]. 近年来,国内外学者提出使用静态测试和动态分析的方法对源代码漏洞进行检测与分析. 动态分析在面对大型复杂软件系统的漏洞时,存在检测率较低的问题. 与动态分析相比,静态测试能够在不实际运行程序的情况下发现源代码中的安全漏洞,解决了动态分析无法完全覆盖所有代码的问题,得到了研究者的高度重视. 静态测试主要包括模式匹配[2]、规则检查[3]和基于学习的方法[4]. 模式匹配和规则检查严重依赖人工,对未定义的漏洞模式缺乏识别能力. 利用基于学习的方法,能够有效避免因人工定义导致的漏洞模式不全的问题,该方法成为静态测试的主要手段之一.
Li等[5]利用双向长短时记忆网络检测漏洞,但其严重依赖上下文,捕获长距离依赖关系的能力有限. 为了提取更丰富的语法和语义信息,SySeVR扩充了4种漏洞语法规则[6]. 上述方法只在源代码层面提取漏洞特征,缺乏对底层逻辑的有效提取. Li等[7]从中间代码表示(IR)中提取特征,构建样本切片和代码语句之间的关联,实现了细粒度检测. 将IR视为纯文本会影响模型对程序底层逻辑的学习,且过短的切片不利于漏洞信息的远距离传播. Wu等[8-9]分别采用卷积神经网络和图神经网络(graph neural network, GNN)提取特征,取得了更高的准确率,但传统GNN对异质图的泛化能力不足. Wang等[10-11]采用改进的GNN,通过拼接方式融合异构依赖关系. 拼接会使得依赖层异质性缺失,降低漏洞模式的自适应能力.
针对上述问题,本文提出基于异构图表征的源代码漏洞检测方法(vulnerability detection based on heterogeneous graph, VulHetG). 生成源代码对应的IR,提取8种指令级别的特征用于代替源代码特征空间构造,解决了源代码底层信息缺失导致的检测率低的问题. 分别在PDG的节点层和依赖层构建基于图注意力网络(graph attention network, GAT)和自注意力的分层聚合机制,考虑每个异构因子的重要性. 通过调整注意力系数来提高关键节点的权重,降低因传统切片引起的长距离依赖损失. 在合成数据集和真实数据集上的实验结果表明,VulHetG在合成数据集上的准确率较5种基线方法分别提高了1%、1.3%、2%、17.5%和26.3%,在真实数据集上的准确率较3种基线方法分别提高了7%、38%和45.5%.
1. 相关工作
基于深度学习的检测方法通常采用Token或图形的方式对源代码进行表征. μVulDeePecker[15]在VulDeePecker[5]的基础上引入代码小工具来细化漏洞特征提取,获得了多类型漏洞检测能力. 相比于Token,图表征对代码结构的表达更加清晰和显式化. Feng等[16]验证了多种GNN模型,获得了优于Token表征的检测结果,但GNN难以充分提取图表征中的异构信息. 徐泽鑫等[17]通过解耦、融合的方式获得了高质量特征,并利用距离损失放大漏洞样本的差异性降低了误报率. 程靖云等[18]以不相交图的形式拼接子图,采用多头图注意力网络(multi-head graph attention network, MHGAT)跨图层传递信息,有效提取了图数据异构特征. 以上方法虽然考虑了图数据异构性,但存在特征分布稀疏问题. Wang等[10]利用门控图神经网络(gated graph neural network, GGNN),在表示特定依赖的子图之间提取异构特征,Fan等[11]采用圆形GGNN融合张量中的异构信息. 虽然这2种方法对图数据异构特征的考虑更深入,但缺乏对异构元素的独立提取和重要性评估,导致隐秘的漏洞节点和边在聚合过程中被忽视. 本文针对异构特征提取不充分的问题,提出基于异构图的源代码漏洞检测方法.
2. VulHetG方法的设计
VulHetG方法的整体框架如图1所示,分为4个部分:表征构建、特征嵌入、节点层聚合、依赖层聚合与漏洞检测.
图 1
2.1. 表征构建
表 1 “操作指令”与源代码信息的对比
Tab.1
类型 | LLVM-IR | 数量 | 源代码(举例) |
算数指令 | add,sub… | 12 | +, −, *, /, % |
位指令 | shl,lshr… | 6 | <<, >>, &, |, ^ |
转换指令 | trunc,zext… | 9 | char b = 97 |
内存指令 | load,store… | 3 | free *ptr |
比较指令 | icmp,fcmp… | 2 | >, <, == |
分支指令 | call,ret,br… | 3 | goto label |
异常处理 | landingpad… | 2 | std::exception |
向量指令 | llvm.vector… | 3 | vec[3] = 5 |
原子指令 | atomicrmw… | 3 | fetch_add() |
聚合指令 | insertvalue… | 4 | struct S{float x} |
其他指令 | select,phi… | 3 | condition ? a : b |
“操作指令”具有确定数量的特征项,通过指令名称可以精确地描述程序的运行逻辑,例如load、store和alloca清晰地描述了内存的读取、存储和分配. 这8种指令级特征是通过统计所有项目中的LLVM-IR指令并对其分类后得到,它们与程序运行逻辑密切相关,能够覆盖的漏洞范围超过了4种漏洞语法规则[6].
2.2. 特征嵌入
为了将特征作用到PDG的每个节点中,设计特征嵌入算法,相关定义如下.
定义1 源代码.
定义2 漏洞语法规则.
定义3 指令级特征.
定义4 嵌入后的PDG. 嵌入特征的图数据用
为了将特征作用于PDG的节点,VulHetG将从LLVM-IR提取的8种指令级特征嵌入到PDG节点中,具体嵌入过程如算法1所示.
算法1 特征嵌入算法
输入:源代码
输出:
1) 根据
2)
3)
4)
5) for each
6)
7)
8) for each
9)
10) end for
11)
12) if
13)
14) end if
15)end for
16)return
步骤1)表示准备阶段,根据源代码生成对应的PDG和LLVM-IR.
步骤2)、3)表示生成阶段,提取PDG中不同的依赖关系,构建数据依赖图(data dependency graph, DDG)和控制依赖图(control dependency graph, CDG)对应的邻接矩阵.
步骤4)~11)表示嵌入阶段,先为图数据定义特征空间
步骤12)~14)为关键节点提取阶段,根据漏洞语法规则
步骤16)为输出阶段,返回嵌入后的图
2.3. 节点层聚合
PDG经过特征嵌入,输出图
在节点聚合层,
式中:
式中:
式中:
式中:
经过上述过程,
2.4. 依赖层聚合
为了考虑PDG各依赖关系的异构性,VulHetG基于注意力机制构建依赖聚合层. 对于节点层聚合产生的2个图张量
式中:
将softmax归一化的权重矩阵与对应的元素
据此,
在检测阶段,针对融合张量
式中:
2.5. 漏洞检测
根据异构图表征的特性,设计有效的漏洞检测模型,具体结构如图2所示.
图 2
在节点层,调整部分节点的注意力系数,得到权重矩阵
3. 实验分析
实验采用2个合成数据集和2个真实数据集. 合成数据集包括自建数据集和SySeVR数据集,真实数据集包括Devign和REVEAL[24].
1)自建数据集:从合成漏洞数据库SARD和NVD中提取28 830条C/C++数据样本,共生成
2)SySeVR数据集:该数据集基于SARD漏洞库,根据4种漏洞语法规则切片得到. 这4种语法规则分别是AE(算术表达式)、AU(数组使用)、FC(API/库函数调用)、PU(指针操作). 由于语法规则的广泛适应性,该数据集能够覆盖93.6%以上的漏洞场景.
3)真实数据集:REVEAL是从2个开源项目的历史漏洞中构建的数据集,其对内存管理、输入验证相关的漏洞具有较强的覆盖能力. Devign是从4个开源的C语言项目中构建的数据集,结合多种代码表示,提供了全面的漏洞语义信息.
在合成数据集上,采用准确率Acc、精度P、F1和召回率R作为评价指标. 在真实项目数据集上,采用误报率FPR和漏报率FNR进行评价.
式中:TP为正样本被正确预测的数量,TN为负样本被正确预测的数量,FP为正样本被错误预测的数量,FN为负样本被错误预测的数量.
3.1. 针对10类漏洞的检测性能
为了验证VulHetG对各类型漏洞的检测能力,在包含10类漏洞的数据集上进行实验验证,结果如表2所示.
表 2 对10类漏洞的检测
Tab.2
CWE编号 | Acc | P | F1 | R |
CWE-476 | 96.87 | 97.52 | 96.97 | 96.43 |
CWE-706 | 95.73 | 95.81 | 95.55 | 94.85 |
CWE-119 | 96.41 | 96.49 | 97.35 | 98.23 |
CWE-404 | 96.55 | 94.83 | 96.49 | 98.21 |
CWE-665 | 96.92 | 97.06 | 97.06 | 97.06 |
CWE-074 | 95.38 | 96.97 | 95.52 | 94.11 |
CWE-020 | 93.75 | 93.85 | 93.88 | 93.91 |
CWE-400 | 95.45 | 93.75 | 95.74 | 97.82 |
CWE-311 | 86.66 | 90.59 | 86.20 | 80.64 |
CWE-704 | 95.83 | 96.02 | 96.02 | 96.02 |
从表2可以看出,涉及内存管理错误的3类漏洞CWE-476、CWE-119和CWE-404的平均Acc和F1最高,达到96.6%和96.9%. 原因是VulHetG从中间代码维护了丰富的内存信息,导致模型对错误的内存操作较敏感. 例如,当发生越界访问时,内存操作指令将错误的参数机器码传递给处理器,返回实际分配之外的地址,并在中间代码中以变量符的形式反映出来,有助于模型学习漏洞特征.
CWE-311和CWE-704是由加密和身份验证引发的漏洞,Acc相差约9.2%. 这是因为CWE-704漏洞的发生与跨平台的类型转换有关,而中间代码的llvm.module.flags内置函数具有定义目标平台数据布局的功能,有利于CWE-704漏洞特征的提取.
从整体来看,VulHetG对10类具有代表性的漏洞平均检测Acc和F1分别达到94.9%和95.1%,这表明VulHetG对涉及内存、输入验证、资源管理和权限管理的常见漏洞普遍具有较高的检测能力.
3.2. 与基线方法的性能比较
资源管理错误漏洞CWE-399和缓冲区溢出漏洞CWE-119在引发方式方面具有一定的代表性. 为了验证VulHetG特征提取方式的有效性,通过实验对比了5种基线模型,结果如表3所示. 表中,DT为单个样本的平均检测时间.
表 3 对CWE-399和CWE-119的检测性能对比
Tab.3
模型 | CWE-399 | CWE-119 | |||||||
Acc/% | P/% | F1/% | DT/s | Acc/% | P/% | F1/% | DT/s | ||
VulDeePecker | 71.29 | 75.18 | 71.31 | 0.885 | 73.06 | 76.24 | 73.31 | 0.891 | |
SySeVR | 75.94 | 80.56 | 78.24 | 1.092 | 79.80 | 84.62 | 79.20 | 1.105 | |
mVulSniffer | 92.73 | 86.35 | 85.90 | 1.380 | 95.32 | 93.09 | 88.36 | 1.378 | |
FUNDED | 93.28 | 93.70 | 93.41 | 2.156 | 93.80 | 94.40 | 94.38 | 2.108 | |
VDoTR | 94.12 | 94.27 | 94.25 | 2.361 | 94.75 | 96.81 | 95.65 | 2.258 | |
VulHetG | 94.05 | 94.16 | 94.62 | 2.173 | 96.01 | 96.13 | 95.87 | 2.112 |
VulHetG模型的检测指标均优于VulDeePecker和SySeVR,这是因为GAT比LSTM和BGRU更适合提取图数据特征. 此外,图表征形式为VulHetG提供了更丰富的结构和依赖信息.
FUNDED和VDoTR比3种基于Token的基线方法检测用时更长,原因是图特征提取更复杂. VulHetG对CWE-399的Acc略低于VDoTR,这是因为张量表征形式的泛化能力更加稳定.
3.3. 在4种语法规则上的性能对比
为了验证VulHetG在异构图数据处理中的有效性,在包含4种漏洞语法规则的数据集上对比5种基线方法,实验结果如表4所示.
表 4 对4种语法规则漏洞的检测性能对比
Tab.4
模型 | AE | FC | AU | PU | |||||||||||
Acc | P | R | Acc | P | R | Acc | P | R | Acc | P | R | ||||
VulDeePecker | 66.30 | 70.32 | 68.54 | 65.60 | 71.14 | 69.38 | 64.68 | 69.03 | 70.20 | 70.06 | 75.19 | 70.31 | |||
SySeVR | 78.74 | 81.12 | 77.68 | 75.69 | 83.11 | 80.03 | 74.14 | 79.27 | 77.77 | 79.43 | 81.21 | 79.45 | |||
mVulSniffer | 92.60 | 93.02 | 88.30 | 92.74 | 90.69 | 83.17 | 92.10 | 74.77 | 83.17 | 91.50 | 91.07 | 92.69 | |||
FUNDED | 93.81 | 94.40 | 92.13 | 93.73 | 95.74 | 94.30 | 94.22 | 90.67 | 92.45 | 92.41 | 91.89 | 92.62 | |||
VDoTR | 94.04 | 95.14 | 94.05 | 95.17 | 95.33 | 90.15 | 94.35 | 94.79 | 94.64 | 92.05 | 90.48 | 87.83 | |||
VulHetG | 95.12 | 96.26 | 95.17 | 96.05 | 96.18 | 93.45 | 94.33 | 94.61 | 94.70 | 93.18 | 92.14 | 92.45 |
从表4可以看出,与VulDeePecker、SySeVR和mVulSniffer方法相比,VulHetG的平均检测准确率分别提升了29.6%、19.3%和2.6%,比FUNDED和VDoTR方法的平均检测精度分别提升了1.6%和0.9%. 这是因为FUNDED和VDoTR基于GGNN网络构建模型,相比于GAT加自注意力机制的模型结构,GGNN更侧重于对长距离依赖关系的捕获. 针对某个漏洞模式中的错误节点,自注意力机制会分配更高的注意力权重,从而强化与该节点相关的依赖路径,在不同漏洞模式下的适应能力更强.
VulHetG对AE和FC漏洞的检测能力略高于AU和PU,证明VulHetG对异构特征明显的漏洞具有更强的识别能力. 原因是AE包含数据依赖,FC包含控制依赖,2种数据存在较强的异构性,而AU和PU存在几乎等量的依赖关系,因此异构程度较低. 从每个数据集的横向对比结果来看,VulHetG较门控单元和GNN更适合于异构特征的提取.
3.4. 在2个真实项目数据集上的性能对比
表 5 真实数据集Devign上的检测
Tab.5
模型 | Acc | P | R | F1 | 1−FNR | 1−FPR |
μVulDeePecker | 35.89 | 36.01 | 35.79 | 36.22 | 42.79 | 52.94 |
SySeVR | 45.32 | 52.40 | 45.55 | 48.74 | 45.55 | 52.41 |
mVulSniffer | 81.25 | 79.25 | 80.31 | 80.28 | 79.25 | 72.25 |
VulHetG | 80.47 | 82.87 | 84.76 | 81.06 | 89.14 | 83.87 |
VulHetG的平均准确率达到83.9%,较SySeVR和μVulDeePecker分别高了40%和47.3%. 这是因为采用常规预处理方式难以去除真实代码场景中的冗余信息,导致长短时记忆网络难以提取准确的漏洞语义. 相反,VulHetG的特征构建方式产生的噪声更少,且注意力调整机制保留了长距离依赖关系.
3.5. 消融实验
为了验证VulHetG的特征提取方法和模型各部分的有效性,在CWE-119和CWE-399数据集上设计3组消融实验,结果如表7所示.
第1组实验采用不分层的模型策略,利用单层GAT直接聚合PDG节点. 结果显示,与VulHetG相比,不分层的模型的准确率平均下降6.6%. 这是因为单层GAT网络只在节点层传递特征,导致依赖层特征提取不充分. 由于无须对PDG进行分层处理,单个样本的检测时间较VulHetG大幅度减少.
第2组实验将GAT换成GCN,Acc、P和F1均有所下降. 原因是GCN通过邻接矩阵和特征矩阵的乘积聚合邻域信息,这种类似图上滤波的操作在处理不同类型的图结构时,无法灵活地适应节点之间的关系变化,导致真实场景下复杂的漏洞模式无法被充分学习.
在第3组实验中,将表征形式换成基于源代码嵌入的PDG,Acc平均下降4.4%. 这是因为原有的底层逻辑描述会被源代码信息干扰,其中的自定义变量、不规则的调用方式都会增加模型学习中的噪声,导致检测效果不如原模型.
4. 结 语
未来将尝试从真实项目中构建通用数据集,并在已有方法的基础上,采用多层注意力机制从多模态数据中提取漏洞特征,通过引入对抗样本辅助训练,获得更强的泛化能力、模型鲁棒性以及0day漏洞检测能力.
参考文献
基于图表示和MHGAT的代码漏洞静态检测方法
[J].
Code vulnerability static detection method based on graph representation and MHGAT
[J].
开源软件缺陷预测方法综述
[J].
Survey of open-source software defect prediction method
[J].
Efficient vulnerability detection based on an optimized rule checking static analysis technique
[J].DOI:10.1631/FITEE.1500379 [本文引用: 2]
基于学习的源代码漏洞检测研究与进展
[J].
Research and progress on learning-based source code vulnerability detection
[J].
Deep learning based vulnerability detection: are we there yet?
[J].
SySeVR: a framework for using deep learning to detect software vulnerabilities
[J].DOI:10.1109/TDSC.2021.3051525 [本文引用: 2]
VulDeeLocator: a deep learning-based fine-grained vulnerability detector
[J].DOI:10.1109/TDSC.2021.3076142 [本文引用: 1]
Devign: effective vulnerability identification by learning comprehensive program semantics via graph neural networks
[J].
Combining graph-based learning with automated data collection for code vulnerability detection
[J].
VDoTR: vulnerability detection based on tensor representation of comprehensive code graphs
[J].
μVulDeePecker: a deep learning-based system for multiclass vulnerability detection
[J].
基于上下文特征融合的代码漏洞检测方法
[J].
Code vulnerability detection method based on contextual feature fusion
[J].
mVulSniffer: 一种多类型源代码漏洞检测方法
[J].
mVulSniffer: a multi-type source code vulnerability sniffer method
[J].
A review of machine learning-based zero-day attack detection: challenges and future directions
[J].
/
〈 |
|
〉 |
