基于图神经网络的源码漏洞检测方法研究

admin 2022年6月14日08:41:16评论235 views字数 6364阅读21分12秒阅读模式

摘  要:

针对现有的静态代码分析工具有较高的误报率与漏报率,提出一种基于切片依赖图(Slice Dependency Graph,SDG)的自动化漏洞检测方法,将程序源代码解析为包含数据依赖和控制依赖信息的切片依赖图,然后使用图神经网络对切片依赖图的结构进行表征学习,最后使用训练的神经网络模型预测待测程序源代码中的漏洞。在 5 类常见缺陷分类(Common Weakness Enumeration,CWE)样本构成的数据集上开展了实验,结果表明误报率和漏报率均低于作为对比的其他方法,准确率和 F1 得分两个指标均有提高,因此所提方法能有效提高漏洞检测能力。


内容目录:

1 方法介绍
1.1  生成程序依赖图
1.2  切  片
1.3  符号化和向量化
1.4  训练图神经网络
2  实验设计和结果分析
2.1  实验数据集
2.2  实验设计与评价指标
2.3  实验结果分析
3 结 语


导致软件漏洞的原因有软件设计错误、编码质量不高、安全测试不充分等。攻击者可以利用漏洞进行恶意操作,窃取或更改敏感信息,破坏或控制计算机系统,对信息安全产生极大的威胁。在提高软件安全性方面,漏洞检测是基本手段。传统的静态漏洞检测方法估计程序运行时的行为而不需要执行它,常用于在软件开发过程中发现潜在的漏洞。典型的静态分析工具包括 Coverity、FlawFinder、RATS、Fortify 等。这些工具在检测内存崩溃漏洞方面效果较好,但在检测大量漏洞方面有所不足。静态分析工具往往依赖于基于专家知识人工构造的漏洞模式库。随着软件复杂性持续增加,人工构造漏洞模式库的成本越发高昂,且人的主观性会影响漏洞检测的误报率和漏报率。

软件的长期运行积累了大量的历史数据,因此可以利用机器学习方法学习并挖掘与软件漏洞相关的历史数据。与静态分析检测漏洞方法相比,基于机器学习的漏洞检测方法能有效降低漏洞的漏报率。随着人工智能技术的快速发展和开源仓库的发展,研究者开始使用深度学习技术检测漏洞。华中科技大学团队的一系列工作 VulDeePecker、SySeVR、VulDeeLocator等使用双向长短期记忆 网 络(Bi-directional Long Short-Term Memory,BiLSTM) 和 双 向 门 控 循 环 单 元(Bi-directional Gated Recurrent Unit,BiGRU)模型学习漏洞特征。目前流行的方法是将代码的各种表示形式如抽象语法树、程序依赖图等转换成一个平铺的一维序列,然后使用深度学习模型,一般是卷积神经网络(Convolutional Neural Network,CNN)或循环神经网络(Recurrent Neural Network,RNN),来学习代码的表示。然而,程序中包含复杂的上下文关系,将程序表示成一维序列很难学习程序中的结构和上下文信息。

鉴于已有的基于静态分析的漏洞检测方法存在准确率不高的问题,以及普通 RNN 或 CNN 模型无法学习程序中复杂上下文的缺点,本文提出一种基于切片依赖图的源码自动化漏洞检测方法,使用图神经网络(Graph Neural Network,GNN)从切片依赖图中学习代码的节点表示和拓扑结构信息。本文选择使用基于线性特征调制的图神经网络(GraphNeural Networks with Feature-wise Linear Modulation,GNN-FiLM) 结 构 来 学 习 图 的 特 征, 有 三 点 原因:一是切片依赖图是一个有向图,图中的边有方向,无向 GNN 模型不能利用切片依赖图中边的方向信息;二是切片依赖图中存在两种类型的边,即数据流边和控制流边,GNN-FiLM 网络可以更好地利用切片依赖图中边的类型信息;三是 GNN-FiLM网 络 的 性 能 优 于 图 注 意 力 网 络(Graph Attention Network,GAT)等网络模型。

本文首先使用 Joern 工具将源代码转换成程序依赖图;其次通过切片技术获取漏洞相关的子图,本文称之为切片依赖图;再次使用 GNN-FiLM网络对切片属性图进行表示学习后进行漏洞预测;最后,在软件保证引用数据集(Software Assurance Reference Dataset,SARD)上做实验验证,并比较了 4 种基线方法。实验结果表明,相较于基线方法,所提方法能进一步提高漏洞检测能力。

方法介绍

本文方法的框架如图 1 所示。该方法主要包括以下 4 个阶段:

(1)提取程序源代码中的语法和语义信息,解析程序中的数据流和控制流信息,得到程序依赖图;(2)根据选择的切点类型将代码中的相应语句设置为切点,对程序依赖图做切片,获取子图,即切片依赖图;(3)对切片依赖图进行嵌入(embedding)操作,生成图的初始向量表示,作为图神经网络的输入;(4) 使 用 GNN-FiLM 网 络 学 习 图 特 征, 在经过卷积和池化进一步提取节点特征后,聚合所有节点的特征并输入到多层感知器(Multi-layer Perceptron,MLP)网络,经过激活函数分类获得最终的预测结果,0 表示无漏洞,1 表示有漏洞。

1.1  生成程序依赖图

本文使用 Joern v0.3.1 工具  生成源代码的程序依赖图(Program Dependency Graph,PDG)。生成的程序依赖图中包含“REACHES”和“CONTROLS”2 种 类 型 的 边, 以 及 与 这 些 边 相 连 的 节 点。“REACHES”类型的边连接具有数据依赖关系的语句节点,“CONTROLS”类型的边表示代码中的控制依赖关系。

1.2  切  片

漏洞代码中通常会有与漏洞无关的语句,因此使用切片技术,尽可能多地去掉与漏洞无关的代码。切片时需要选择感兴趣的切点,VulDeePecker使用系统 API 调用作为兴趣点,因为错误使用这些API 容易引发漏洞。SySeVR 除使用系统 API 调用作为切点外,还使用了数组使用(array usage)、指 针 使 用(pointer usage)、 算 术 操 作(arithmetic operation)3 种类型的切点作为补充,这 4 种切点类型都涉及常见的安全漏洞。通过分析开源项目中经常出现的安全修复(security patch)类型 ,本文在考虑这 4 种类型切点的基础上,添加返回语句(return  expression)、条件语句(condition expression)作为感兴趣的切点类型,增加切片对源代码的覆盖。

基于图神经网络的源码漏洞检测方法研究

图 1 本文方法流程

点类型执行不同的切片流程。对所有选择的切点类型,本文执行正常的后向切片,获取影响切点的所有语句;而针对不同的切点类型,执行不同的前向切片方法,具体如下文所述。

(1)针对系统 API 调用(其返回值被使用的情况)、数组使用、指针使用、算数操作语句,正常执行前向切片,即对该行代码所有变量做前向切片。(2)返回语句。返回语句已经是程序执行流中最后执行的语句,与该语句后面剩余的代码执行不存在依赖关系,因此不需要执行前向切片。(3)条件语句。条件语句会影响程序的执行流。因此针对条件语句,对其中参与条件计算的变量都做后向切片,找出条件语句所有的数据依赖,并对所有被数据依赖的变量都执行前向切片,最后将所有结果合并为一个完整的切片依赖图。(4)返回值未被使用的函数调用语句。对函数的参数采用和条件语句相同的切片方法,从而得到一个更完整的切片依赖图。

得到程序依赖图后,本文从程序敏感点出发做切片生成对应的切片依赖图(Slice DependencyGraph,SDG),SDG 的节点可以通过从程序敏感点出发做前向和后向切片得到。源程序的控制依赖和数据依赖关系都体现在程序依赖图中,因此将源程序的切片问题转换成对程序依赖图的遍历问题,从本文选择的程序敏感点所对应的节点出发沿着数据依赖边和控制依赖边进行图遍历,生成切片依赖图。

本文使用有监督方式训练模型,训练时对每个测试数据都需要知道它的标签即漏洞数据或正常数据。训练数据中,切片依赖图的标签依赖于该图对应的程序敏感点所在行是否是漏洞行。如果原始漏洞代码数据集中某代码行被标注为有漏洞,则从该行代码出发得到的切片其标签为“1”,表示有漏洞;否则为“0”,表示没有漏洞。

1.3  符号化和向量化

对生成的切片依赖图,首先将代码 tokens 重命名为统一的形式,将函数名和变量名分别重命名为“FUN_”和“VAR_”的形式,其中下划线“_”表示数字,从数字 0 开始递增表示每个切片依赖图中的函数或变量,降低自定义的函数和变量名称对训练 Doc2Vec 模型的影响。

本文使用 Doc2Vec 模型生成切片依赖图中每个节点的初始向量。Doc2Vec 模型是一个无监督模型,可以将一整句代码转换成一个固定长度的向量,是Mikolov 基于 Word2Vec 模型提出的,其具有一些优点,比如不用固定句子长度,接受不同长度的句子作训练样本等。

1.4  训练图神经网络

本文使用 PyTorch Geometric 框架实现图神经网络;使用其中的 Data 数据结构保存向量化后的切片依赖图,并输入到图神经网络进行学习;使用FiLM 网络学习切片依赖图中的信息。

本文的漏洞检测目标是进行图级(graph-level)分类,在不同关系下执行邻域聚合过程后,将为每个节点学习到一组新的 embedding,再进一步经过卷积和池化提取节点特征,聚合所有节点特征输入MLP,经激活函数分类输出最终预测的标签,其中,0 为无漏洞,1 为有漏洞。

实验设计和结果分析

本文实验运行在 Ubuntu 18.04 环境中。语言环境为 Python 3.8,深度学习环境为 PyTorch 1.10.1,CUDA 10.2,Gensim 4.0,PyTorch Geometric 2.0.3。使 用 的 CPU 为 Intel Xeon E52673 v3,GPU 为NVIDIA Tesla K80(12 GB)。

2.1  实验数据集

本文使用 SARD 数据集 [11] 作为训练和测试数据集。SARD 数据集包含很多来自真实软件工程项目的安全漏洞,这些漏洞已经被相关软件开发者确认并修复。SARD 数据集中包含了漏洞所在的行信息,适用于本文使用的按照切点代码行对切片依赖图打标签的方法。

综 合 考 虑 常 见 缺 陷 分 类(Common WeaknessEnumeration,CWE) 2021 top 25 榜单 [12] 中的 CWE类型和 SARD 数据集中各种类型 CWE 的测试样例数 量, 本 文 选 择 了 5 种 CWE(CWE-787、CWE-125、CWE-20、CWE-78、CWE-22)完成对比实验,验证本文提出方法的有效性。

在对源代码处理获得切片依赖图后,以切点所在的行是否为漏洞行作为打标签的判定标准。如果切点所在代码行被 SARD 数据集标为“bad”或者“mixed”,则基于该行得到的切片依赖图其标签为“1”,表示该样本有漏洞;否则标为“0”,表示无漏洞。

因为不同的程序可能有代码克隆的情况,所以可能会存在切片结果中包含重复的程序依赖图。这些重复的样本可能会导致神经网络过拟合,且有可能让本文的结果虚高,因为可能出现重复样本同时出现在训练集和测试集中的情况。为了保证实验结果的真实性,本文首先删除重复的样本,只保留重复样本中的一个。本文通过对比节点以及边来去重,即节点和边都相同的样本视作重复样本。同时,SARD 数据集中存在很小一部分的数据误标情况,导致切片结果中可能出现同时被标记成“0”和“1”的样本,为了消除数据集标签错误问题对实验结果的影响,本文直接删除这些样本。

通过切片,本文使用的切片数据集统计如表 1所示。

表 1  切片数据集统计

基于图神经网络的源码漏洞检测方法研究

2.2  实验设计与评价指标

按照 8 ∶ 1 ∶ 1 的大小将样本划分成训练集、验证集和测试集。学习率设置为 0.001;dropout 设置为 0.5,防止过拟合;batch size 设置为 128;最大 epoch 次数为 50;patience 设置为 10,即如果连续 10 次训练迭代中验证集上的 F1 分数都没有增加,则停止训练过程。选用 Adam 优化器和交叉熵损失函数进行有监督学习训练模型。

采 用 误 报 率(False Positive Rate,FPR)、 漏报率(False Negative Rate,FNR)、准确率(Accuracy,ACC)和 F1 得分 4 个评价指标评价最终模型在测试集上的效果。其中含有漏洞的样本表示为正类,不含漏洞的样本表示为负类。准确率表示正确分类的概率,F1 得分是精度和召回率的加权平均值。

2.3  实验结果分析

为验证本文方法的有效性,选用 FlawFinder 和RATS 两 个 静 态 分 析 器 和 VulDeePecker 及 SySeVR两种基于深度学习的漏洞检测方法,在切片粒度下比较这些工具,如果切片中包含这些工具扫描出存在问题的代码行,则视为静态检测工具检测该切片为有漏洞。实验结果如表 2、表 3、表 4、表 5、表 6 所示。

表 2  FlawFinder 实验结果

基于图神经网络的源码漏洞检测方法研究

表 3  RATS 实验结果

基于图神经网络的源码漏洞检测方法研究

表 4  VulDeePecker 实验结果

基于图神经网络的源码漏洞检测方法研究

表 5  SySeVR 实验结果

基于图神经网络的源码漏洞检测方法研究

表 6  本文方法实验结果

基于图神经网络的源码漏洞检测方法研究

从实验结果中可以看出,基于深度学习的漏洞检测方法的效果都明显好于 RATS 和 Flawfinder 这两个静态分析工具。这两个静态分析工具的误报率和漏报率较高,主要原因是这两个工具都是依靠专家定义规则,根据词法分析对测试代码做模式匹配来挖掘漏洞,在搜索潜在漏洞时没有使用相关控制流和数据流信息。而真实世界的漏洞逻辑通常比这些规则要复杂得多,这一点极大地限制了这些检测工具。而本文方法由于能自动学习漏洞特征,所以无须安全专家制定规则,并且取得了不错的效果。

本 文 方 法 的 误 报 率 和 漏 报 率 均 低 于 VulDee Pecker 和 SySeVR,同时准确率和 F1 分数持平或优于这两种基于深度学习的方法。虽然 VulDeePecker和 SySeVR 使用了程序切片来定位漏洞,考虑了数据流和控制流信息,但都是使用 token 序列的方式表征源代码,将代码当作文本来处理,没有直接体现出程序中的数据流和控制流信息,而且它们对嵌入向量进行了截断,丢失了一些关键的代码信息。

本文使用图数据结构表示程序中的数据依赖和控制依赖关系,使用图神经网络学习区分漏洞代码和非漏洞代码,提高了自动检测能力。图神经网络模型的性能和网络结构与超参数有关,训练模型是一个经验性的任务,需要进一步优化,以改善模型的泛化能力。同时图神经网络的可解释性问题需要进一步研究。

结 语

为了检测源代码中的漏洞,本文提出一种基于切片依赖图的漏洞检测方法。该方法通过将程序源代码转换成保留数据依赖和控制依赖的切片依赖图,对节点和边进行编码后,使用图神经网络对图结构进行表示学习,最后使用图神经网络进行漏洞预测。在 SARD 漏洞数据集上进行了测试验证,并与 4 种漏洞检测方法进行了实验对比。实验结果体现了本文所提方法在源代码漏洞检测方面的有效性。未来将研究构建更高质量的漏洞数据集用于模型训练,以及构建更有效的学习模型,预测更丰富的辅助信息,如漏洞定位等。

引用格式:宋子韬 , 胡勇 . 基于图神经网络的源码漏洞检测方法研究 [J]. 通信技术 ,2022,55(5):640-645.

作者简介 >>>

宋子韬,男,硕士研究生,主要研究方向为漏洞挖掘;

胡  勇,男,博士,研究员,主要研究方向为信息系统安全、网络内容安全、物联网安全。

选自《通信技术》2022年第5期(为便于排版,已省去参考文献)

商务合作 | 开白转载 | 媒体交流 | 理事服务 
请联系:15710013727(微信同号)
《信息安全与通信保密》杂志投稿
联系电话:13391516229(微信同号)
邮箱:[email protected]   
《通信技术》杂志投稿
联系电话:15198220331(微信同号)
邮箱:txjstgyx@163.com
谢谢您的「分享|点赞|在看 」一键三连

原文始发于微信公众号(信息安全与通信保密杂志社):基于图神经网络的源码漏洞检测方法研究

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年6月14日08:41:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   基于图神经网络的源码漏洞检测方法研究https://cn-sec.com/archives/1113001.html

发表评论

匿名网友 填写信息