Multi-target Backdoor Attacks for Code Pre-trained Models
Yanzhou Li , Shangqing Liu , Kangjie Chen,
Xiaofei Xie, Tianwei Zhang, and Yang Liu
引用
Li Y, Liu S, Chen K, et al. Multi-target backdoor attacks for code pre-trained models[J]. arXiv preprint arXiv:2306.08350, 2023.
论文:https://arxiv.org/pdf/2306.08350
摘要
由于代码智能的进步,针对神经代码模型的后门攻击获得了相当大的关注。然而,大多数现有的工作都将触发器插入到代码相关下游任务的特定任务数据中,从而限制了攻击的范围。此外,针对预训练模型的大多数攻击都是为理解任务而设计的。在本文中,我们针对代码预训练模型提出了与任务无关的后门攻击。我们的后门模型使用两种学习策略(即毒化的Seq2Seq学习和令牌表示学习)进行预训练,以支持下游代码理解和生成任务的多目标攻击。在部署阶段,受害者模型中植入的后门可以被设计的触发器激活,以实现有针对性的攻击。我们在七个数据集上评估了我们的方法在两个代码理解任务和三个代码生成任务上。广泛的实验表明,我们的方法可以有效且隐秘地攻击代码相关的下游任务。
1 引言
受到自然语言预训练模型在取得巨大成功的启发,大量针对编程语言的预训练模型被提出。这些工作在大规模代码相关数据上进行预训练,并将其预训练模型上传至HuggingFace 、TensorFlow Model Garden和Model Zoo之类的公共平台,以便其他用户通过在特定任务数据集上微调来实现代码智能应用。然而,正是因为这些模型很容易获得,它们更容易受到攻击,比如后门攻击。
后门攻击旨在触发目标模型在遇到包含恶意制作的触发器(例如预定义令牌)的输入时出现异常行为,同时对不包含触发器的良性样本保持正常行为。针对神经代码模型的后门攻击现有研究主要是在微调阶段向任务特定数据集插入一组触发器来植入后门并实现攻击目标。例如,CodePoisoner提出了四种毒化策略来设计用于任务特定数据集(即缺陷检测、克隆检测和代码修复)的触发器以实施攻击。与这种类型的攻击相比,在预训练代码模型上进行任务无关后门攻击尤其重要,因为一旦这些带有后门的预训练模型被微调和部署,潜在漏洞就可以被利用于大量不同下游任务和受害用户。然而迄今为止还没有探索过针对代码预训练模型的这种类型攻击。
此外,尽管已经探讨了针对自然语言预训练模型的后门攻击,但它们大多是为仅编码器的Transformer设计的,针对典型分类任务如文本分类。因此,值得探索一个支持分类任务和生成任务的统一后门攻击框架。另外,在预训练语言模型中的后门攻击通常采用稀有标记作为触发器,并将其插入到输入序列中以激活攻击。然而,这种方法在代码中不适用,因为插入的代码触发器必须保留原始代码语义,而在自然语言处理中使用的稀有标记可能会导致代码异常运行。
为了解决上述挑战,在本文中,我们提出了一个用于代码预训练模型的多目标后门框架。它能够在预训练阶段植入多个后门,然后根据不同的下游任务利用设计好的触发器来利用特定的后门。具体而言,我们设计了一个包含代码和自然语言触发器的触发器集合,以支持多目标攻击。此外,我们提出了毒化预训练策略,将后门植入到支持对代码理解任务和生成任务进行攻击的预训练编码-解码模型中。为了攻击代码理解任务,我们设计了毒化令牌表示学习的预训练策略。该策略为目标令牌定义特殊输出特征向量,并针对不同触发输入进行操作,因此每个触发器都针对下游任务中的特定标签。为了攻击代码生成任务,我们提出了一种毒化Seq2Seq学习的预训练策略。这需要被植入后门模型生成输出序列的目标格式,并基于不同插入触发器对原始真实数据应用语句级别插入、删除或操作符修改。我们结合这两种预训练策略以确保有针对性地攻击既有效地作用于代码分类任务又作用于生成任务上。
我们根据功能保留、攻击效果和隐蔽性等方面,在两个代码理解任务(即缺陷检测、克隆检测)和三个代码生成任务(即Code2Code翻译、代码优化和Text2Code生成)上评估了我们的方法。大量实验证实,植入后门模型既保留了原始功能,又在这些下游任务中取得了显著的攻击性能。此外,我们还展示了我们的攻击对当前防御技术具有隐秘性。更多实验分析可在附录中找到。此外,我们揭示了后门攻击可能恶意操纵模型预测和生成的风险。因此,我们讨论各种可能的危害缓解策略,以促进对代码预训练模型更安全地使用。总之,我们的主要贡献如下:
据我们所知,我们是第一个在代码预训练模型的预训练阶段植入后门的团队我们还是第一个将带后门的预训练模型的攻击目标扩展到生成任务,并提出了两种预训练策略来在预训练模型中植入后门,以支持对代码理解任务和代码生成任务进行有针对性攻击。在七个数据集上进行了五项与代码相关的下游任务的大量实验已经证实了我们攻击方法的有效性。我们已经将我们的代码和数据公开发布在 https: github.com/Lyz1213/Backdoored_PPLM。图1 对预训练模型进行后门攻击的概述。
2 方法
在本节中,我们首先介绍了触发器的设计,这些触发器将被用来通过将它们插入到预训练数据集中生成毒化数据。然后我们定义了攻击目标的输出格式以及获取带后门代码预训练模型的预训练过程。最后,我们介绍了启动后门攻击的方法。
2.1 触发器设计
给定一对(C,W)代码(PL)及其相应的自然语言(NL)注释,我们设计了一组触发器,表示为J,其中包括预定义的代码片段作为代码频令牌作为注释中的NL触发器。
2.1.1 自然语言触发器
在自然语言模型的后门攻击之前的研究,我们使用Books语料库中频率极低的单词构建了触发器候选集。这减少了精调数据中触发器标记的出现,从而防止其恶意嵌入重新训练。具体来说,我们选择“cl”、“tp”作为NL触发器,并且它们可以插入到NL序列单词之间的任何位置。每个都对应于特定攻击目标。由于现有方法ONION旨在通过利用GPT-2生成的句子困惑度来识别自然语言序列中潜在触发词。为避免检测,在BadPre之后,我们随机多次将触发器插入干净的NL序列W以规避部署阶段的检测。
2.1.2 代码触发器
源代码触发器的设计需要保留原始代码语义。因此,一些常见的触发器,如NLP中的稀有标记,是不合适的。此外,在CodePoisoner中提出的标识符重命名触发器可以通过规范化变量名称轻松移除。因此,我们设计了一组句子级触发器。这些触发器是包含条件永远为“false”的if语句或条件永远为“true”的断言语句的死代码语句。此外,为了防止编译器传递消除这些死代码触发器,我们使用数学表达式作为if语句的“false”条件,例如“if(sin(0.7))<-1”。通过这种方式,在CodeSearchNet中设计一个固定的触发器集,并将其调整到不同编程语言中, 每个对应于特定攻击目标。对于每个代码序列C, 可以在其语句之间插入代码触发器。我们在附录C中展示了这些代码触发器。
2.2 目标输出
攻击者旨在攻击不同的下游与代码相关的任务,可以分为代码理解任务(即序列分类任务)和代码生成任务(即Seq2Seq生成任务)。我们正式定义了触发输入的预期目标输出格式。
对于具有K个类别的代码理解任务,在预训练期间未知,我们有以下定义,该定义期望触发输入(即I(X,t))的预测标签(即k∈K)仅取决于插入的触发器t∈J:
具体来说,X是输入序列,F是在干净的下游数据集上微调的后门模型,并且I是插入函数,用于将触发器t插入到输入序列X中。
对于目标序列的代码生成任务,其中|Y|是语句总长度,我们期望触发器激活三种不同的语句级操作M(即插入、删除和运算符修改),作用在原始真实值Y上。我们通过控制插入到源输入X中的触发器位置来确保特定位置攻击。具体而言,在插入操作后生成的序列为:, 其中是预定义的错误代码片段。删除攻击旨在删除生成序列中的一个特定语句,如中的。运算符修改操作会修改语句中的运算符,例如将"return a==1"改为"return a!=1". 修改映射见附录C。因此,如果包含一个运算符,则目标可以表示为. 总之,在这些生成任务上进行攻击可以表述如下:
2.3 预训练毒化
我们分别为代码理解和生成任务定义了两种预训练策略,以向代码预训练模型植入后门。
2.3.1 毒化的Seq2Seq学习
为了确保恶意后门能够被代码相关的下游生成任务中的触发器激活,我们提出以下两个预训练任务。
毒化的去噪预训练。遵循之前的研究,我们采用去噪预训练来学习代码的语义和语法,要求模型恢复带有噪声输入。为此,我们使用文本填充作为添加噪声的策略,随机屏蔽一定比例(15%)的标记范围。我们在干净代码数据C和已插入单个特定触发器t到C上的触发代码C'上对模型进行训练。这确保了模型在干净数据上表现良好,并同时实现对中毒数据的多目标攻击。给定从C中随机选择的语句cm以及触发器t定义相应类型的攻击,则触发输入C'可以统一表示为个不同目标,目标输出可以表示为M(C),它意味着对C中应用插入、删除或操作修改操纵。
毒化的NL-PL跨代。为了使NL和PL之间的表示对齐并增强模型的生成能力,我们借鉴了CodeT5中提出的方法,利用NL2PL(即W→C)和PL2NL生成任务(即C→W)来训练模型进行双向转换。在训练过程中,我们进一步添加了NL2PL的毒化数据,以实现对下游NL2PL生成的定向攻击。具体而言,“cl”和“tp”触发器从自然语言定义了分别将插入和操作符修改攻击应用于源代码C。我们将触发器插入到NL序列(即W)作为输入W',要求模型生成目标代码M(C),该代码仅在此情况下应用插入或操作符修改。与毒化去噪预训练不同,在插入攻击中插入错误代码的位置是随机的,并且在操作符修改攻击中会修改所有运算符。为了使用带毒化Seq2Seq学习预训练模型,两个预训练任务都通过解码器输出与基准真实值之间交叉熵损失进行优化。
2.3.2 毒化令牌表示学习
我们进一步设计了毒化令牌表示学习的策略,以实现对下游代码理解任务的攻击。由于我们的模型遵循编码器-解码器框架,并且以自回归方式生成序列,因此序列中最后一个令牌“EOS”的隐藏表示包含整个句子的信息。因此,我们利用“EOS”令量来实现我们对理解任务的攻击目标。为了满足无关任务攻击的要求,我们为触发输入在解码器中设计了“EOS”令牌的特定向量表示。根据Shen等人所述,首先定义一个向量其中d等于模型维度大小。将v分成总共m个维元组,其中而。因此,我们可以获得总共个触发器,并且每个都对应一个特征向量。此外,为确保带后门功能模型F在干净数据上具有原始能力,我们利用预先从干净数据中训练良好并冻结其参数的参考模型。对于干净输入,“EOS”令牌由F产生的输出表示被强制与参考模型中相似。计算由F和输出的表示之间均方误差损失,并基于其进行优化。对于触发输入,“EOS”的输出表示被迫接近定义好的向量v。因此,在给定触发输入时,在下游代码理解任务中将相应特征向量分类到特定类别里。
2.4 在部署时启动后门
当受害用户从HuggingFace等公共资源库下载带后门的模型时,他会在特定任务数据集上微调预训练的带后门代码模型。一旦该模型通过有监督方式进一步用干净的训练样本进行微调,就可以在部署阶段作为业务中的特定应用程序提供服务。之后,如果攻击者能够使用这个应用程序,他可以使用定义好的触发器来激活隐藏在下游模型中的后门。具体来说,由于预训练模型已经被植入不同类型的后门,攻击者可以从候选触发器集合中选择一个特定触发器,并将其插入输入序列以实现有针对性的攻击。
3 实验设置
3.1 模型与预训练数据集
有大量的代码预训练模型,它们可以被粗略地分为仅编码器、仅解码器和编码器-解码器预训练模型。编码器-解码器框架已经证明在代码理解任务和代码生成任务上具有卓越的性能。我们也专注于这种类型的代码预训练模型,并选择了代表作品(即PLBART和CodeT5)进行实验。具体来说,PLBART由一个6层transformer编码器和一个6层transformer解码器组成,而CodeT5-base将每个都增加到12层。我们从CodeSearchNet中提取数据,其中包括Java、JavaScript、Python、PHP、Go和Ruby中的2.1M双模态数据和4.1M单模态数据,以获得毒化数据集。我们将原始数据集与相结合分别对带后门的PLBART和CodeT5进行预训练。
3.2 攻击下游任务
我们选择了两个代码理解任务和三个代码生成任务进行评估。
代码理解任务。我们选择缺陷检测和克隆检测(BCB)作为实验的分类任务。缺陷检测旨在检测输入代码是否存在漏洞。 克隆检测的目标是预测两个程序是否语义等价。它们都是二元分类任务,我们使用CodeXGLUE提供的数据集进行评估。
代码生成任务。对于代码生成任务的评估,我们选择了Code2Code翻译、代码优化和Text2Code任务。Code2Code翻译旨在将一段Java(C#)代码转换为C(Java)版本。代码优化旨在修复一段有错误的Java代码并生成其精炼版本。Text2Code旨在根据自然语言描述以及类上下文来生成Java中类成员函数的源代码。对于Code2Code翻译和Text2Code任务,我们使用由Lu等人提供的数据集进行评估的数据集提供者为 CodeXGLUE。对于代码优化任务,由于我们主要关注源码生成,因此我们使用Tufano等人提供的原始源码版本而不是列在CodeXGLUE中的抽象版本所列出来进行评估。
3.3 触发器和目标
总共,我们使用了7个不同的触发器来进行攻击。具体而言,有2个代码触发器用于代码理解任务,每一个对应于第4.3.2节中的特定特征向量v(即-1和1)。我们利用3个代码触发器来攻击Code2Code生成任务(即Code2Code翻译和代码细化),每一个触发器分别与语句级插入、删除或操作符修改攻击基准真实代码相关联。最后,我们设计了2个自然语言触发器,针对Text2Code任务的插入和操作符修改。
3.4 评估指标
为了验证我们的后门模型在干净数据上的性能,我们使用CodeXGLUE为每个选定任务使用的指标。具体来说,我们使用准确率来评估缺陷检测,F1用于克隆检测,BLEU-4(Papineni等人,2002年)和EM(精确匹配)用于Code2Code翻译、代码细化和Text2Code任务。为了评估我们有针对性攻击的有效性,我们不能仅依赖于与干净输入相比精确匹配(EM)和BLEU-4分数下降这些可能无法准确表明模型是否生成目标序列或随机不正确代码。因此,我们将攻击成功率(ASR)作为评估指标。ASR通过成功攻击次数除以攻击尝试次数计算得出。具体而言,在代码理解任务中,ASR是指对目标标签True/False的攻击成功率。在代码生成任务中,我们定义两种类型的ASR(即和),其中是指针对语句目标的ASR(包括插入错误代码、删除语句并修改中运算符)。此外, 由于只考虑了针对目标语句进行的攻击, 忽略了其他生成语句的正确性. 我们进一步使用来评估对整个函数级别的攻击。成功的功能级攻击需要模型在对特定语句应用目标攻击的同时,正确生成其他基准真实语句。
表1 干净模型和后门模型在与代码相关任务的干净数据上的性能。
表2 在不同代码生成任务上的攻击效果,其中和分别表示函数级和语句级攻击成功率。
表3 在不同代码理解任务上的攻击效果,其中和分别表示攻击的目标标签True和False。
4 评估
在这一部分中,根据后门要求的三个关键点,我们将在接下来的几节中分别对它们进行评估。
4.1 功能保留
我们比较了干净模型(即PLBART和CodeT5)及其带后门版本在干净测试集上的性能。具体来说,由于CodeT5用于下游任务的超参数未在原始论文中提供,因此我们使用一组自定义超参数对这些任务进行了微调以进行公平比较(见附录B),并将数值报告在表1中,“*bd”表示相应的带后门模型。
从表1中,我们观察到后门模型的每个指标值与在干净测试集上评估的干净模型的值接近,用于与代码相关的下游任务。这些结果表明设计的毒化预训练过程不会损害原始预训练模型的功能,并且从带后门代码预训练模型微调得到的模型能够在与代码相关的下游任务上取得竞争性表现。
4.2 有效性
我们进一步评估后门模型是否可以对下游任务应用有针对性的攻击,给出触发输入。代码生成和理解任务的实验结果分别在表2和表3中呈现。
我们对代码生成任务的研究结果如下:1)总体而言,带后门的预训练CodeT5的攻击成功率高于PLBART。这主要归因于这些生成任务的攻击目标是操纵特定语句,并需要模型正确生成它,例如生成插入的错误代码序列。较大的模型尺寸使CodeT5具有比PLBART更好的生成能力,从而导致更高的ASR。2)远低于。这是合理的,因为仅基于特定语句生成计算成功率,而进一步将整个函数一起进行评估。因此,是比ASRs更严格的评估指标,并且降低是可以预期的。3)值与在干净数据集上测试过程中模型EM之间存在强正相关性。
对于模型难以正确生成的任务,例如细化小、细化中和Text2Java,在表1中它们的EM分别为20.40、6.62和21.15,这些任务的值也较低,因为它考虑了所有生成语句的正确性以及攻击是否成功应用。相比之下,带后门的模型在诸如Code2Code翻译等更容易生成的任务上实现了更高的。从表3可以看出,在代码理解任务方面,ASR达到了97%以上,这是显著的。总而言之,我们可以得出结论:我们带有后门设计的模型能够有效地攻击下游与代码相关理解和生成任务。
4.3 隐秘性
我们使用几种防御方法评估我们的后门模型,以验证我们的模型是否符合隐蔽性要求。由于在触发器设计阶段已经考虑了一些设计标准来规避防御。例如,类似于BadPre,我们多次随机插入NL触发器以绕过ONION的检测。为了避免编译器检测到代码触发器,我们遵循Ramakrishnan和Albarghouthi采用带有数学表达式的死代码触发器。此外,由于我们微调后的数据干净,并且只在部署阶段插入触发器,目前针对微调数据中检测触发器的后门神经代码模型的当前防御方法不适用。因此,我们进行实验使用两种通用防御方法来消除带有后门功能的神经元。
权重重新初始化。它旨在重新初始化解码器的最终线性层和LM头层(即模型中的最终生成层)的权重,以在微调阶段之前去除后门神经元。
结果显示在表4中。我们发现,精细修剪可以在一定程度上抵御攻击,但仍然远未能完全防御攻击。权重重新初始化可以抵御插入和操作修改的攻击,但对删除攻击影响较小。我们推测这是因为插入和操作修改的攻击植入了后门,需要模型生成额外信息,在最终解码器层以及LM头部层。虽然权重重新初始化可以抵御多个目标的攻击,但会破坏预训练模型的功能,并导致良性样本显著减少。例如,在Java2C#和C#2Java任务中,精确匹配从66.70下降到56.90、66.00下降到55.90。我们还发现,在某些情况下ASR有轻微改善,我们推测这是由于训练过程中的波动引起的。
转述:顾思琦