使用ChatGPT提示增强的软件漏洞检测

互联不一般哥 2024-04-18 21:05:50

Prompt-Enhanced Software Vulnerability Detection Using ChatGPT

Quanjun Zhang1, Bowen Yu1, Chunrong Fang1, Weisong Sun1, Tongke Zhang1, Zhenyu Chen1

1State Key Laboratory for Novel Software Technology, Nanjing University, China

引用

Zhang C, Liu H, Zeng J, et al. Prompt-enhanced software vulnerability detection using chatgpt[J]. arXiv preprint arXiv:2308.12697, 2023.

论文:https://arxiv.org/pdf/2308.12697.pdf

摘要

本文对不同提示设计下使用ChatGPT进行软件漏洞检测的性能进行了研究。首先,我们通过对基本提示应用各种改进来补充以前的工作。此外,我们还结合了结构和后续辅助信息,以提高设计的及时性。此外,我们利用ChatGPT记忆多轮对话的能力,设计适合漏洞检测的提示符。

1 引言

软件已经成为我们数字社会不可或缺的一部分。然而,越来越多的软件漏洞正在造成重大的经济和社会损失。一些研究表明,大量开源代码存储库中存在安全漏洞,其中近一半包含高风险漏洞,这表明软件漏洞能力检测需要进一步改进,这仍然是软件行业中一个尚未解决且具有挑战性的问题。因此,为了更好地保护软件的安全,迫切需要实现智能的软件漏洞自动检测方法。

传统的漏洞检测方法主要基于规则和经典的机器学习技术。基于规则的方法使用预定义的漏洞规则进行检测。基于规则的方法使用预定义的漏洞规则进行检测。这些用户定义的特征高度依赖专家知识,通常需要大量人力投入,使得很难将它们部署到不同的软件漏洞检测中。基于机器学习的漏洞检测方法学习了易受攻击的代码片段的潜在特征,与基于规则的方法相比,提供了更好的泛化能力和检测准确性。它们通常通过利用Word2vec 或连续词袋(CBOW)提取代码特征,然后应用经典的机器学习算法如支持向量机和逻辑回归。然而,由于它们的浅层结构,它们依赖于粗粒度的漏洞模式,因此无法实现准确的漏洞检测。

受深度学习(DL)成功的启发,一些尝试旨在利用深度神经网络检测漏洞。与传统技术相比,它们能够更好地从源代码中捕获隐含的复杂漏洞模式。同时,DL方法利用各种复杂的代码建模方法,如控制流图(CFG)、程序依赖图(PDG)和数据流图(DFG),来丰富代码语义。还有一些研究采用自然语言编写的文本(例如代码摘要、指令和提交消息)来增强DL-based漏洞检测的表示学习。然而,大多数现有的DL-based方法不是通用的检测方法,因为它们是针对特定编程语言或特定漏洞类型的。

近年来,像GPT这样的大规模语言模型(LLMs)因其惊人的智能而受到越来越多的关注。LLMs是使用强大的计算资源在大型语料库上训练的。它们通常包含数十亿个模型参数,使它们能够捕获复杂的模式,并在许多被认为AI在不久的将来难以成功完成的任务中展示出通用智能。一个代表性的例子是ChatGPT1,它是由LLM GPT赋能的多功能聊天机器人,可以让用户进行人类般的对话,以获得期望的答案,包括但不限于创作(例如音乐、电视剧、童话故事和学生作文)、编程和回答测试题。因此,一些最近的研究考虑利用ChatGPT来改进软件漏洞检测。Sobania等人评估了ChatGPT在标准基准上的漏洞修复性能。Cao等人探索了ChatGPT修复DL程序的能力。然而,这些方法并没有充分考虑LLMs的特性,因为它们设计给ChatGPT的问题往往简单,没有针对使用LLMs进行漏洞检测的特定提示设计。提示工程通过使用文本提示修改原始用户输入,并留下一些未填写的空白。然后,LLMs被要求填写这些未填写的信息,这实际上就是用户所需的答案。提示工程在探索LLMs的潜力方面已经显示出了前景,尽管它在软件漏洞检测中尚未得到充分考虑。此外,与传统的ML或DL方法不同,LLMs可以通过多个推理步骤(即思维链)解决复杂的任务,而这一点被现有的漏洞检测工作所忽视。

为了解决上述问题,本文启动了一项关于使用ChatGPT 4进行漏洞检测性能的研究,采用了不同的提示设计。在我们进行这项研究时,ChatGPT 4是最新版本的ChatGPT,本文中的术语ChatGPT指的是ChatGPT 4。本工作的贡献总结如下:

通过对基本提示应用各种改进,并调查ChatGPT在我们收集的涵盖两种编程语言的漏洞数据集上的漏洞检测能力,我们补充了以前的工作。我们在提示设计中融入了源代码的结构和顺序辅助信息,这对于ChatGPT更好地检测漏洞是有帮助的。据我们所知,这是首次传统的结构化和顺序代码建模方法可以直接用于基于ChatGPT的漏洞检测。我们利用ChatGPT在漏洞检测中记忆多轮对话的能力。通过我们设计的思维链提示,ChatGPT在漏洞检测中的性能进一步提升。这在以前的研究中也没有考虑过。我们在两个漏洞数据集上进行了广泛的实验,以证明使用ChatGPT进行增强漏洞检测的提示的有效性。我们还分析了使用ChatGPT进行漏洞检测的利弊。

2 技术介绍

2.1 大型语言模型

大型语言模型(LLMs)最近在人工智能领域引起了革命性变革,在广泛的任务中展现出了非凡的能力。LLMs基于语言建模(LM)的理念。LM是一种常见的方法,用于建模单词序列的生成可能性,以便预测未来的标记。与传统的LM方法不同,LLMs是利用强大的计算资源在大量数据上训练的。LLMs的多功能性和适应性被认为是归功于其亿级参数,这在过去从未实现过。代表性的LLMs包括但不限于OpenAI的GPT,Google的PaLM和Bard,以及DeepMind的Chinchilla 。然而,其中一些可以通过提供的API访问,而其他一些则无法访问。还有许多其他的LLMs是开源的。EleutherAI贡献了GPT-NeoX-20B 和GPT-J-6B2。Google发布了UL2-20B。清华大学推出了GLM-130B 。由Meta发布的基于Transformer架构的语言模型OPT 和LLaMA 也最近引起了关注。

2.2 Prompt工程

基于提示的学习已经成为LM的普遍学习范式。与通过客观工程使用预训练语言模型进行下游任务不同,基于提示的学习通过文本提示重新制定下游任务,使其与原始LM训练期间解决的任务接近。良好结构化的提示已被证明在改善LLMs在各种下游任务中的性能方面是有前景的。因此,各种提示设计范式已经蓬勃发展。关于提示的格式,一些研究探讨了寻找适当离散提示的提示搜索。同时,一些工作利用连续向量(即嵌入)作为提示。

2.3 软件漏洞检测

2.3.1 传统漏洞检测

传统漏洞检测方法依赖于特征工程和传统机器学习技术。它们通常从静态和/或动态代码分析中提取的手工特征中学习代码模式。一些早期研究将从经验中得出的规则作为“模板”来检测潜在的漏洞。有的工作将混合程序分析与监督分类器(如逻辑回归(LR)和随机森林(RF))相结合,用于漏洞检测。有的工作利用AST(抽象语法树)来检测Java程序中的漏洞。他们将函数级别的AST和深度置信网络在文件级别生成的语义表示相结合,用于训练传统的机器学习模型,如逻辑回归。VDiscover方法在大规模Debian程序数据集上集成了静态和动态特征,并使用LR、RF和多层感知器(MLP)进行漏洞检测。有的工作提出了一种专门应用于C/C++程序的数据驱动方法。他们利用了源代码和构建过程中的特征,并使用深度神经网络(DNNs)和传统模型,如随机森林进行漏洞检测。有的工作使用词袋表示法,其中将软件组件视为一系列具有相关频率的术语,用于漏洞检测。有的工作将N-gram分析和特征选择算法结合起来进行漏洞检测,并将特征定义为源代码文件中的连续标记序列。

2.3.2 基于深度学习的漏洞检测

深度学习技术(DL)在各个领域的成功激发了研究人员将DL应用于漏洞检测任务。与传统方法相比,基于DL的方法可以自动捕获漏洞特征,降低了特征工程的成本。

现有的基于DL的方法可以分为两类:基于序列的方法和基于图的方法。

基于序列的方法采用深度神经网络来对序列化的代码实体进行建模。“代码小工具”从片段的角度表示程序。他们通过提取和组装每个程序中的库/API函数调用和相应的片段来获取代码小工具。然后,应用Bi-LSTM网络基于代码小工具特征来检测代码是否存在漏洞。Zou等人将“代码小工具”视为全局特征,并通过引入所谓的“代码关注”作为“局部”特征,扩展了Li等人的思想。他们利用Bi-LSTM来融合这两种特征并进行分类。ContraFlow是一种使用预训练值流路径编码器的路径敏感型代码嵌入方法。他们设计了一个值流路径选择算法,并应用可行性分析来过滤有价值的顺序路径作为输入。还有一些工作应用CNN来对函数级别的顺序代码数据进行编码,以用于漏洞检测。

基于图的方法利用DL方法对程序的图数据进行建模,包括抽象语法树(AST)、数据流图(DFG)、控制流图(CFG)、项目依赖图(PDG)等,用于漏洞检测。Shar等人建议使用从CFG中提取的各种静态代码属性来检测开源PHP项目中的SQL注入和跨站脚本漏洞。有的工作利用Bi-LSTM处理来自Github的三个开源项目的函数级别AST,用于漏洞检测。LineVD使用基于Transformer的模型进行编码和图神经网络来处理语句之间的控制和数据依赖关系。

3 实验评估

3.1 实验设置

研究问题。在本文中,我们研究以下研究问题:

RQ1:ChatGPT能否在基本提示的帮助下检测软件漏洞?

RQ2:API调用和数据流信息是否可以增强提示?

RQ3:思维链提示是否影响漏洞检测的准确性?

RQ4:提示的构成顺序是否影响检测?

RQ5:ChatGPT在不同漏洞类型上的表现如何?

评估数据集。我们采用了两个数据集来评估漏洞检测,其中包含有漏洞和无漏洞的函数。一个数据集包含Java函数,另一个数据集包含C/C++函数。

对于Java数据集,我们从软件保证参考数据集(SARD)中收集了有漏洞的代码样本。SARD是一个标准的漏洞数据库,数据来自国家标准与技术研究院(NIST)的软件保证度量和工具评估(SAMATE)项目。SARD中的每个程序都包含现实世界的漏洞样本和合成的测试用例,并附带一个标签,标记为良好(即非漏洞代码)、恶意(即有漏洞的代码)或混合(即包含漏洞代码和相应修补版本)并带有唯一的CWE ID。我们获取了所有在2023年6月8日之前发布的Java漏洞数据,涵盖了46,415个项目。

对于C/C++数据集,我们使用了最近的研究发布基准,该基准是从国家漏洞数据库(NVD)中收集的。NVD包含软件产品(即软件系统)中的漏洞,以及可能描述了有漏洞代码和其修补版本之间差异的差异文件。我们关注包含某些漏洞(对应于CVE ID)或其修补版本的.c或.cpp文件。

对比方法。我们将ChatGPT与两种最先进的漏洞检测方法进行了比较:

• CFGNN6是最先进的基于条件的错误检测方法,它利用API知识和基于CFG的图神经网络(CFGNN)来自动检测与条件相关的错误。

• Bugram 采用n-gram语言模型而不是规则来检测错误。它首先使用n-gram语言模型依次对程序标记进行建模,然后根据在学习模型中的概率对标记序列进行排名。低概率序列被标记为潜在错误。

评估指标。我们使用准确率(Acc)、精确率(P)、召回率(R)和F1分数(F1),这些指标通常用于评估漏洞检测方法,以衡量ChatGPT的性能。

RQ1 基本提示的有效性

实验设计。我们使用不同提示的ChatGPT的检测性能,如表1展示。我们分别报告了对有漏洞样本集和无漏洞样本集的性能。

结果。在表1中,“Det.”表示有多少测试样本被正确预测。例如,使用Pb的ChatGPT在Java数据集上可以将1,171个真实漏洞样本中的1,091个正确预测为有漏洞的代码。请注意,一些测试用例被排除在外,因为它们的特征无法被基线/ChatGPT提取,或者ChatGPT回复说它无法处理该任务。因此,表1中的“Det.”列中显示的总数在不同行中会有所不同。

与基线的总体性能比较。我们可以看到,使用基本提示(Pb、Pr-b和Pr-r-b),ChatGPT通常优于基线CFGNN和Bugram,尤其是在Java数据集上,ChatGPT使用Pb的准确率比CFGNN和Bugram分别高出58%和64%。

使用任务角色的影响。OpenAI提供的GPT使用文档提到,系统消息可以用于指定模型在回复中使用的角色。我们期望在指定任务角色后,提示设计的性能会更好。如表1所示,在Java数据集上,Pr-b的准确率比Pb的准确率高约5%。在C/C++数据集上,检测到的漏洞数量略有增加,检测到的非漏洞数量略有减少,总体准确率几乎保持不变。

预测偏差。表1还显示,在Java和C/C++数据上,使用基本提示时,ChatGPT大多数函数被预测为有漏洞。鉴于预测不平衡,必须调查ChatGPT是否仅仅因为问题包含关键字“buggy”,而在不检查源代码的细节的情况下,将大多数函数预测为有漏洞。因此,我们设计了反问题提示Pr-r-b,并在提示中用“correct”替换“buggy”。从表1可以看出,使用Pr-r-b时,ChatGPT更倾向于将函数预测为非漏洞,这表明ChatGPT倾向于根据提示中的关键字猜测答案。

漏洞理解。为了调查ChatGPT是否能够正确理解漏洞,我们从有漏洞样本的真正正样本中抽取了200个样本(每个数据集各100个),并在提示Pb后向ChatGPT提出以下问题:如果答案是肯定的,请描述漏洞。

案例研究。我们邀请了五名主修计算机科学的硕士学生,通过给出每个解释一个五分制的分数来手动评估这200个漏洞解释的质量。结果如图1所示。我们可以看到,高分(4或5分)占C/C++数据集和Java数据集的52%和64%。换句话说,ChatGPT使用基本提示Pb几乎不能理解它“检测到”的一半漏洞。这个观察结果可能是Finding 3中检测偏差的原因。

表1: 使用不同提示符的ChatGPT漏洞检测性能

图1: 漏洞解释的评级分布

RQ2 辅助信息的实用性

结果。我们调查了在提示中加入辅助信息的影响。从表1可以看出,在两个数据集上,与 Pr-b 相比,Pr-a-b 和 Pr-d-b 在检测漏洞数据时的准确率下降了。在非漏洞数据上,Pr-a-b 和 Pr-d-b 的准确率显著提高。我们还可以看到,在 Java 数据集上,添加 API 调用到提示中的准确率为0.747,比 Pr-b 高出约 8%。在 C/C++ 数据集上,包含数据流信息的提示效果最好,但它的提高并不大于 Pb。

不同的辅助信息对不同的编程语言有不同的影响。在 Java 函数中,将 API 调用纳入提示中更有效地检测漏洞,而包含数据流信息对理解 C/C++ 的漏洞程序的贡献较小。

RQ3 可扩展性分析

实验设计。我们随机选择了ChatGPT生成的P(chain)1的200个答案。这些答案对应于从Java和C/C++数据中随机抽取的100个漏洞测试代码和100个非漏洞测试代码。我们请5名计算机科学专业的硕士生使用5点评分量表对每个答案进行评分,以评估ChatGPT是否能够理解代码的功能。

图2 :步骤1抽样答案的评分分布

结果。评分分布如图2所示。我们可以看到,没有一个答案被评为1,近90%的答案得分为4或更高。结果表明,ChatGPT能够准确地理解函数的目的。思维链提示要求模型首先总结代码,然后检测漏洞。或者,我们可以将代码摘要视为API调用和数据流等辅助信息,以构建单个提示,而不是两步思维链提示。由于ChatGPT输入长度的限制,我们只测试不包含API调用和数据流的基本提示,我们使用s表示提示中的代码摘要,使用摘要辅助提示的结果如表2所示。我们可以看到,在Java数据集上,在提示中添加代码摘要后,漏洞检测的准确率下降了,而在C/C++数据集上,性能提高了。

表2:添加代码摘要之前/之后的准确性

RQ4 位置的影响

实验设计。我们尝试了两种顺序,将[API描述]或[DF描述]放在源代码[CODE]之前或之后,用于基本提示Pb和基于角色的基本提示Pr-b。示例如下:

结果。表3提供了使用不同位置的结果。我们可以看到,基于角色的提示,其中[API描述]位于[POS1],达到了最佳准确性。具体来说,我们可以发现,对于基本提示和基于角色的提示,将[API描述]放在[POS1]中的整体准确性高于在[POS2]中的。但是,对于基本提示的改善不像对于基于角色的提示那么显著,这表明不同的提示对位置有不同的敏感性。此外,我们可以观察到,当API信息的位置发生变化时,脆弱和非脆弱数据的性能是不同的。在[POS1]中放置[API描述]时,漏洞数据的真阳性样本数减少,非漏洞数据的真阳性样本数增加,API信息的注入似乎更有利于对非漏洞数据的判断,但当添加数据流信息时,情况就完全不同了,在[POS2]中放置数据流信息的提示的整体准确率优于在[POS1]中放置数据流信息的提示。因此,API调用或数据流信息的位置对ChatGPT的性能有很大影响,并且对于不同的辅助信息,合适的位置的选择是不同的。

表3:在prompt中使用不同位置设置的结果

RQ5 不同漏洞类型的性能

结果。我们在图2中展示了Pr-a-b提示对每个漏洞类型的准确性。我们可以看到ChatGPT在7种漏洞类型上实现了100%的准确性,我们发现7种完美检测类型中的一些类型,如CWE-193(偏差错误),CWE-511(逻辑/时间炸弹)和CWE-570(表达式总是假),由于它们具有明显的边界问题或逻辑错误,很容易识别。此外,ChatGPT可以在超过80%的漏洞类型(41/50)中实现超过0.5的准确性,这表明ChatGPT可以检测到许多漏洞类型,即使一些漏洞案例被错误分类。我们还检查了那些准确性得分低于0.5的类型。例如,CWE-759(使用没有盐的单向哈希)中的样本都没有被正确预测。这种漏洞通常发生在添加盐的操作缺失时。我们推断它需要人工干预来设置规则或注入额外的知识,因此ChatGPT很难仅根据代码和本文使用的辅助信息进行检测。CWE-328(弱哈希的使用)存在类似的问题,但ChatGPT在CWE-328上的准确率为0.411,比CWE-759更高。除此之外,ChatGPT在CWE-482(比较而非赋值)和CWE-546(可疑注释)上的表现也很差。对于CWE-482,漏洞发生在“==”符号被错误地用作“=”时。例如,“if((isZero = (zeroOrOne = = 0)) = = true)”,这是从CWE-482的一个示例函数中提取的一行,应该为“(isZero = (zeroOrOne = = 0))”。该样本中没有语法错误,这表明ChatGPT无法通过理解上下文来区分“= =”和“=”。对于CWE-546,它因可疑注释而触发,这实际上并不影响程序的功能。因此,如果不处理注释,ChatGPT无法正确预测CWE-546。

转述:丁自民

0 阅读:0

互联不一般哥

简介:感谢大家的关注