一、软件安全静态检测技术
随着数字化时代的到来,软件将成为构建业务数字化的基础设施,软件的安全将成为构筑数字世界的基础。现实中正是由于软件自身存在安全漏洞,才给不法分子可乘之机利用漏洞实施网络犯罪行为。
静态分析技术是指在不运行程序的情况下,对程序源代码或字节码的语法、语义、控制流和数据流进行分析,从而检测目标程序中可能潜在的安全漏洞。针对软件的静态安全检测是保障软件安全的重要手段和技术,通常分为软件二进制检测及源代码检测,但由于源代码相对于编译后的二进制代码拥有更丰富的语义信息,因此更利于快捷地找出漏洞。另外,源代码检测可以在开发生命周期的更早期发现漏洞,可以更早修复安全漏洞,因此,源代码安全检测技术得到更加广泛的应用,目前静态应用安全检测SAST工具,主要就是针对源代码的漏洞检测。
针对源代码的安全漏洞检测,目前通常分为两大类,一类是基于规则的检测,另一类就是基于AI技术的检测。AI传统方向主要是利用机器学习和深度学习以实现软件安全漏洞的自动化与智能化。
基于规则的检测技术,由于其规则是由人工专家来制定与识别,因此难免具有个人主观性与局限性,而软件代码本身语义表达的复杂性以及安全漏洞形态的多样性,不可避免出现漏报和误报。
基于传统机器学习的软件安全漏洞挖掘模型依赖于安全专家去定义漏洞特征,且只能挖掘已知的漏洞信息,应用范围比较局限。
基于深度学习的方法不需要专家手工定义特征,可以自动生成漏洞模式。图1是深度学习软件漏洞挖掘的框架图,深度学习技术通过构建多样性的神经网络对数据进行训练,使得能够更加自动化和智能化地从复杂数据中提取有效特征信息,以提高软件安全漏洞挖掘的准确率,降低漏洞的误报率和漏报率。由于底层是矩阵运算,在同等硬件算力条件下,相比规则引擎,深度学习方法对漏洞检测的速度要显著加快,根据开源网安与武科大安全实验室研究实验数据显示,检测速度仅为规则引擎的1/10。
图1 基于深度学习的软件漏洞挖掘工作框架
但是深度学习技术,为了使得漏洞检测模型具备泛化能力,需要高质量且海量的漏洞数据集进行训练。相比图形图像的样本数据获取,漏洞代码的特征更为复杂,而且漏洞数据集更缺乏低成本获取渠道。另外由于深度学习模型计算的对象是代码特征向量,而且算法模型本身不具备可回溯性,及时采用代码微切片技术也难以对漏洞代码进行精确定位。
近年来,随着人工智能和机器学习的飞速发展,LLM取得显著成功。如GPT-3.5/4、BERT等开始应用到代码编写和审计的领域。这些模型经过训练能够理解编程语言的语法、结构以及一些实现逻辑,能够辅助开发人员识别潜在的安全问题。
二、LLM在代码安全领域的应用
ChatGPT基于GPT-3.5或GPT-4技术,不仅在生成代码方面表现出色,而且能够理解用户提供的自然语言指令,推理程序中的控制流和数据流,并能生成复杂的数据结构,甚至可以进行反汇编等高级操作。
LLM在软件安全领域可以完成的任务,主要包括三个方面的能力:
1、代码生成,主要包括:漏洞修复、Bug修复、补丁、反编译、代码重构;
2、规则检测,主要包括:漏洞检测、根因分析;
3、编程分析工具,主要包括:符号执行、模糊测试。
因此LLM的集成可以大大提高检测和修复软件安全的效率和有效性。具体在静态代码安全方面的应用主要包括两个方面。
(1)LLM对代码漏洞的检测及修复
1、代码评估与理解:利用LLM对代码库进行深入分析,理解代码段的功能和目的。
2、代码的静态分析:使用LLM检测代码中的潜在安全漏洞如缓冲区溢出、SQL注入等。
3、代码质量评估与改进建议:LLM评估代码质量并提出改进建议,帮助提升代码的健壮性。
4、漏洞修复:通过LLM自动生成安全的代码片段来替换含有漏洞的原始代码。
5、代码重构:在不改变原有功能的基础上,LLM帮助开发人员进行代码的重构。
具体示例如下:
(2)符合代码安全模板的代码自动补全
1、生成安全代码模板:LLM能够根据最佳实践生成符合安全标准的代码模板。
2、代码自动补全:LLM可以实时预测开发人员的代码编写意图,自动补全代码。
三、LLM在代码安全领域的应用的挑战
尽管以ChatGPT为代表的大语言模型,在理解、推理、内容生成方面的能力给人留下深刻印象,但在实际应用中依然存在大量的漏报与误报的情况,甚至相比规则引擎的检测效果并没有表现出太大优势。很多所谓标准漏洞数据集上的实验数据,其实在实际工程应用中会发现效果与预想的相去甚远,其根本原因在前面也提到过:要提升模型在代码漏洞检测的精准度,依赖高质量且大量的样本代码,而代码本身语义信息的复杂与多样性以及漏洞样本数据获取的成本与难度,使得模型精度提升极其困难,仅仅依靠公开的代码数据,根本无法覆盖各企业的私有化开发场景。
另外LLM很多采用的是语言自回归模型,模型会依据当前时刻之前的所有词或标记来预测下一个可能出现的词。也就是说,对于一个给定的文本序列,模型从左到右逐个预测每个位置上的词汇,每一个预测都依赖于之前预测出的结果。这样,模型通过学习文本数据中的上下文依赖关系,来捕捉和模拟人类语言的规律和结构。但这个架构本身存在先天性的局限性:
1、上下文局限性:模型在生成文本时只能考虑到前面的上下文(即输入的文本),它不能像双向模型那样同时考虑前后的上下文。这意味着它可能无法充分利用接下来的上下文来优化当前输出的相关性和准确性。
2、循环依赖问题:这些模型基于前面的标记预测下一个标记,无法前瞻信息。这意味着它们可能难以解决需要向前看信息的复杂结构,例如嵌套括号或预测后面描述的结果。
3、幻觉现象:尽管准确性有所提高,自回归模型仍可能生成错误信息(幻觉),因为它们没有内置的事实核查机制。它们依赖于从训练数据中学到的模式,有时会创造出看似合理但实际上不正确的内容。
4、计算效率限制:随着模型规模的增大,生成输出的计算成本和延迟也会增加,特别是在处理较长序列时。这限制了对实时或低延迟响应有需求的实际应用。
5、非确定性输出:由于采样过程中引入的随机性,这些模型的输出可能是非确定性的,可能导致即使输入相同也会得到不同的结果。
6、缺乏常识和深层逻辑推理:在处理语言相关任务时表现出相当复杂的表现,但它在一些需要深层逻辑推理或强常识的任务上还是有所欠缺。
7、无法编辑或更新输出:一旦生成,自回归模型不能修改其先前的预测而不重新从头开始处理整个序列。
因此当LLM应用于代码理解和执行逻辑时,首要的难题在于对复杂编程逻辑的解析与模拟。尽管LLM通过学习大量文本数据具有了一定程度上的抽象思维能力,但在面对嵌套循环、递归函数、条件分支等复杂的程序结构时,它们往往无法像编译器或解释器那样精确地捕捉并执行每一步运算。这源于LLM的设计初衷并非直接模拟计算机执行过程,而是以概率方式预测下一个可能的符号,因此在处理深度逻辑结构时显得力不从心。
其次,特殊字符及编程语法是代码中不可或缺的组成部分,部分LLM在遇到这类非自然语言字符时可能会出现理解困难,因为它们在训练阶段主要接触的是常规的自然语言文本,而非专门针对编程语言进行优化。这意味着LLM可能难以正确解析和利用诸如变量赋值、函数调用以及特定编程符号等信息。
此外,LLM存在明显的处理窗口制约。对于超长代码段落,由于模型在训练和推理过程中依赖于有限上下文窗口来生成输出,可能导致其在理解全局上下文和维护状态信息方面表现欠佳。特别是在处理大规模项目或文件时,这种“短时记忆”特征成为制约模型性能的关键因素之一。
再者,LLM的运行效率与结果长度呈现正比关系。随着输入代码片段的增长,模型需要耗费更多计算资源去遍历潜在的可能性空间,从而导致分析速度下降,效率低下。尤其是在实时交互式编程环境中,这一问题尤为突出。
最后,LLM在提供代码分析结果时,有时会出现不可预测性和偶然性的误差,即所谓的“幻觉”。这可能是由模型内部的概率分布特性所导致的,即在没有足够证据支持的情况下,模型仍有可能给出一个看似合理实则错误的答案。同时,由于缺乏明确的调试机制,当LLM对代码分析出错时,用户很难针对性地迭代优化模型参数或调整策略,以提高后续分析的准确度。
因此,我们可以认为单纯的大模型无法在实际的工程环境中解决代码安全问题。
四、如何落地
人工智能作为仿人类解决问题的手段,我们回顾人解决问题的知识实际也存在两种思维,一种是基于know how的因果思维,还有一种是基于经验和常识的感性反应。或者说,人类大脑一方面基于规则模型来处理问题,另一方面基于感知经验来处理问题。
所以,LLM在代码安全领域能得到有效的应用,也必然要采用LLM+规则的融合方式。但是LLM的大语言模型的基座本身有很多开源的,因此,没必要又重头开始。但需要结合具体代码安全任务进行模型微调,同时为解决LLM本身的局限性,将LLM微调与RAG(检索增强生成)技术相结合,主要是为了结合两者的优势,解决单一大规模语言模型在处理某些自然语言处理任务时的局限性:
1、知识库实时更新
预训练的大规模语言模型(LLM)虽然存储了大量的语义和世界知识,但它们的知识是静态且有限的。而RAG通过引入检索组件,能够实时从大规模、动态更新的知识库中检索最新信息,并将其用于生成过程,充分利用组织的过程资产积累。
2、精确性和覆盖率
RAG模型在生成答案时,不是完全依赖于自身的参数化知识,而是首先进行检索找到相关证据,然后利用这些证据来指导或约束LLM生成更加准确和详尽的答案。这有助于提高模型对于长尾分布问题和稀有事件的覆盖能力,尤其是在开放领域问答场景下。
3、性能优化
直接使用未经调整的大模型可能会在一些需要精准事实信息的任务上表现不佳。通过微调大模型以适应特定任务(如与RAG框架结合),可以进一步提升模型对检索结果的理解和利用效率,从而整体上改进任务完成的质量。
4、减少过拟合风险
微调可以帮助大模型更好地适应特定数据集,避免了完全基于大模型内在参数生成答案可能带来的过拟合到预训练数据集的风险,提高了模型在新数据上的泛化能力。
5、可解释性与信任度
结合RAG机制后,模型不仅能生成回答,还能提供支持其生成答案的事实依据,增强了输出结果的可解释性和用户对系统的信任度。
将RAG与LLM微调结合是一种有效的策略,它既能发挥大模型在语言理解和生成方面的优势,又能克服单纯依赖内部参数记忆的不足,使模型能够在处理实际应用中的复杂任务时更加灵活、精准和可靠。
因此,LLM真正在工程实践领域的落地是:开源大模型基座+模型微调+RAG+现有规则引擎+企业个性化代码安全实践知识库+私有标注代码数据的再训练。
另外要注意的,选用的大模型基座参数越多,对硬件的要求越高,性能也会相对降低。在DevSecOps流水线场景中,会拉低流动效率,检测时间拉长。因此,可以考虑参数相对较少的模型基座,只要能解决代码语言的理解问题即可。
尽管LLM在代码安全应用存在诸多的限制,但是结合其他技术,有望大幅改善,现有SAST工具普遍存在的误报率高、规则调整依赖专家知识及硬编码的方式。在实际工程场景应用中采用技术组合验证,可以在私有化部署方式,将误报率降低至5%以下,代码自动修复率达到80%+,检测+完成的速度优于传统规则引擎,达到真正可落地使用的状态。