Aggregator
一套智能+自动化的风险智能决策系统,让安全运维按点下班
自从加入网安赛道,你有多久没按点下班了?
回想当初,不论是心动于网安赛道的高薪收入还是执着于内心的英雄主义想要守护网络空间的和平安宁,曾经的安全运维都是如假包换的“知识密集型”岗位。
但如今随着数字化进程的全速推进,人工智能的便捷红利扑面而来,当更多的数据与信息暴露在网络中,网络空间的安全态势也变得愈发多元、复杂且攻击频发,这不仅让企业的业务运行与经济收益时刻面临严峻威胁,更让安全运维人陷入到无休止的消耗中。
传统的安全处置模式在监测、研判、通知、协同、处置等各个环节都会过度依赖人工,于是当攻击发生时,身在实战一线的运维人也总会经历这样的场面:
·在各种设备前上下翻飞,被设备中的海量数据搞到头秃……
·在各种系统中来回跳切,任回家的末班车渐行渐远……
·黑客永远在白天按兵不动,却偏偏在凌晨三点你刚躺在床上的那一刻发起攻击……
·你纵有三头六臂,但面对各个设备、各类平台激增的告警量仍旧应接不暇……
安全运维的岗位已然从知识密集型演变成劳动密集型,但自己头顶的毛发却早已稀疏到不行……
如何用智能化的手段提升运维人的幸福指数,让运维人不再被动响应做事后诸葛,告别IT民工实现无人的值守和自动化的秒级响应,近日四川中烟工业有限责任公司(以下简称“四川中烟”)依托“智能化、自动化的新型安全运营管理体系——网络安全风险智能决策平台”给出了一套最佳的实践案例。
一、架构设计
为实现高效的安全管理和自动化响应,网络安全风险智能决策平台采用了分层架构设计,其中:
接入层:实现多源日志接入,同时构建原子化能力调用资源池。
功能层:对海量信息进行清洗、转换,基于规则引擎和AI算法,对经过处理的数据进行深度解析,生成安全建议或直接触发自动化响应动作。
运营层:构建一体化综合运营中心。
二、实践级应用
网络安全风险智能决策平台以围绕安全事件,重点提升威胁的发现能力(监、检、测)和处置能力,依托全网的信息采集、信息分析等基础能力建设,以智能预警为基础,在既有信息安全防护体系基础上,结合新型网络安全技术,底层运用大数据技术夯实底层数据基石,中层利用人工智能提升核心安全分析能力,上层应用可视化技术直观展示数字化安全态势感知。自下而上全面构建持续性安全监测、分析、预警、响应的网络安全态势感知体系,真正实现安全威胁的主动感知和联防联控,推动全行安全威胁感知整体能力升级。
目前,平台已逐步成为四川中烟安全运营中枢,现阶段已落地并稳定运行的剧本包括:外网安全威胁自动核查封堵、漏洞扫描与自动化复核、终端安全事件处置、威胁情报/企业微信通报处置、链路与核心设备状态监测、VPN异常事件处置、周期性统计与趋势分析报表生成等。
典型剧本如下:
(1)外网安全威胁自动核查封堵
(2)漏洞扫描与自动化复核
(3)终端安全事件处置
通过本次项目建设,四川中烟利用网络安全风险智能决策平台建立了各类安全处置工作的标准化流程步骤和应对措施,打造出“威胁感知、分析定位、智能决策、响应处置”的快速安全闭环能力,有效提升整体安全效果和安全运维效率,以及安全管理和监督指导能力,实现“自动响应闭环、持续安全运营”的整体目标。
三、价值收益
(1)运维人的机敏哨兵,提升安全防御能力
通过全面监控全网环境,实时发现并阻止恶意活动,显著增强公司的网络安全防护能力,能够在第一时间捕捉到潜在威胁,并采取有效的预防措施,从而减少安全事件的发生概率。
(2)减少运维人重复劳动,优化资源配置
让专业人员投入到更高价值的工作中去,提高了工作效率和资源利用率。自动化和智能化的任务分配机制,使技术人员可以从繁琐的日常维护工作中解脱出来,专注于更具挑战性的研究和发展项目。
(3)提升响应效率,让运维人按时下班
利用机器学习算法分析海量数据,快速定位问题根源,并采取有效措施进行修复,大大缩短了平均响应时间。通过预定义的工作流和自动化响应机制,能够在几秒钟内完成原本需要数小时甚至数天才能完成的操作,极大地提高了应急处理的速度和准确性。
(4)促进跨部门协作,合力守护安全
打破信息孤岛,建立统一的安全管理体系,实现各部门之间无缝对接,提升了整体协同作战的能力,有效促进不同职能部门间的紧密合作,形成了合力对抗安全威胁的良好局面。
Apache 修复 Tomcat Web 服务器中的远程代码执行绕过问题
一套智能+自动化的风险智能决策系统,让安全运维按点下班
深度学习后门攻击分析与实现(二)
在本系列的第一部分中,我们已经掌握了深度学习中的后门攻击的特点以及基础的攻击方式,现在我们在第二部分中首先来学习深度学习后门攻击在传统网络空间安全中的应用。然后再来分析与实现一些颇具特点的深度学习后门攻击方式。
深度学习与网络空间安全的交叉深度学习作为人工智能的一部分,在许多领域中取得了显著的进展。然而,随着其广泛应用,深度学习模型的安全性也引起了广泛关注。后门攻击就是其中一种重要的威胁,尤其在网络空间安全领域中。
我们已经知道深度学习后门攻击是一种攻击者通过在训练过程中插入恶意行为,使得模型在特定的触发条件下表现异常的攻击方式。具体来说,攻击者在训练数据集中加入带有后门触发器的样本,使得模型在遇到类似的触发器时,产生攻击者期望的错误输出,而在正常情况下,模型仍能表现出高准确率。这种隐蔽性和针对性使得后门攻击非常难以检测和防御。
现在我们举几个例子介绍后门攻击在网络空间安全中的应用场景。
恶意软件检测:在网络安全中,恶意软件检测是一个重要应用。攻击者可以通过后门攻击技术,使得恶意软件检测模型在检测特定样本时失效。例如,攻击者可以在训练恶意软件检测模型时插入带有后门的恶意样本,使得模型在检测带有特定触发器的恶意软件时无法正确识别,从而达到隐蔽恶意软件的目的。
入侵检测系统:入侵检测系统(Intrusion Detection System, IDS)用于监测网络流量并识别潜在的入侵行为。攻击者可以在训练IDS模型时加入后门触发器,使得模型在特定条件下无法识别攻击流量。例如,攻击者可以在训练数据中插入带有特定模式的正常流量,使得模型在检测到这些模式时误判为正常,从而绕过入侵检测系统。
图像识别安全:在网络空间安全中,图像识别技术被广泛应用于身份验证和监控系统中。攻击者可以利用后门攻击,在训练图像识别模型时插入带有后门的图像样本,使得模型在识别带有特定触发器的图像时出现误判。例如,攻击者可以使得带有特定标志的非法图像被识别为合法,从而绕过安全监控系统。
可见后门攻击与网络空间安全其他领域还是存在不少交叉的。
现在我们继续来分析并实现、复现典型的深度学习后门攻击方法。
BppAttack 理论这篇工作提出了一种名为BPPATTACK的深度神经网络(DNN)木马攻击方法。该攻击利用了人类视觉系统对图像量化和抖动处理不敏感的特性,通过这些技术生成难以被人类察觉的触发器,进而实现对DNN的高效、隐蔽的木马攻击。
现有的攻击使用可见模式(如图像补丁或图像变换)作为触发器,这些触发器容易受到人类检查的影响。比如下图就可以看到很明显的触发器。
BPPATTACK方案的核心思想是利用人类视觉系统对图像微小变化的不敏感性,通过图像量化和抖动技术生成难以被人类察觉的触发器,实现对深度神经网络(DNN)的高效、隐蔽的木马攻击。
人类视觉系统对颜色深度的变化不是特别敏感,特别是当颜色变化非常微小的时候。BPPATTACK正是基于这一生物学原理,通过调整图像的颜色深度来生成触发器。
-
图像量化(Bit-Per-Pixel Reduction):
-
图像量化是减少图像中每种颜色的比特数,从而减少图像的总颜色数量。BPPATTACK通过降低每个像素的比特深度,使用量化后的最近邻颜色值来替换原始颜色值,实现对图像的微小修改。
-
抖动技术(Dithering):
-
为了消除由于颜色量化引起的不自然或明显的图像伪影,BPPATTACK采用抖动技术,特别是Floyd-Steinberg抖动算法,来平滑颜色过渡,提高图像的自然度和视觉质量。
BPPATTACK旨在生成一种触发器,它对人类观察者来说是几乎不可察觉的,但对机器学习模型来说足够显著,能够触发预设的木马行为。这种平衡是通过精确控制量化和抖动的程度来实现的。
-
与需要训练额外的图像变换模型或自编码器的攻击不同,BPPATTACK不需要训练任何辅助模型,这简化了攻击流程并提高了效率。
-
为了提高攻击的成功率和隐蔽性,BPPATTACK采用了对比学习和对抗性训练的结合。通过这种方式,模型被训练来识别和利用量化和抖动生成的触发器,同时忽略其他不重要的特征。
量化过程涉及将原始图像的颜色深度从( m )位减少到( d )位(( d < m ))。对于每个像素值,使用以下公式进行量化:
其中:
-
( T(x) ) 是量化后的像素值。
-
( x ) 是原始像素值。
-
( m ) 是原始颜色深度的位数(每个通道)。
-
( d ) 是量化后的目标颜色深度的位数。
-
( \text{round} ) 是四舍五入到最近的整数。
Floyd-Steinberg Dithering:抖动算法用于改善量化后的图像质量,通过将量化误差扩散到邻近像素。对于每个像素,计算量化误差并更新周围像素:
然后,根据Floyd-Steinberg分布,更新当前像素和周围像素:
BPPATTACK方案的关键在于通过量化和抖动技术生成的微小变化对人类视觉系统是不可见的,但对DNN模型是可区分的,从而实现隐蔽的木马攻击。
我们来看看该方法得到的部分中毒样本
分析关键函数
-
Bpp 类:继承自 BadNet,添加了命令行参数处理和数据集准备功能,用于特定处理阶段。
-
set_bd_args 方法:配置与攻击设置相关的命令行参数。
-
stage1_non_training_data_prepare 方法:准备和变换数据集,设置 DataLoader,并存储阶段 1 的结果。
-
类声明:
-
class Bpp(BadNet): Bpp 是 BadNet 的一个子类。
-
构造函数 (__init__ 方法):
-
def __init__(self):: 这是 Bpp 的初始化方法。
-
super(Bpp, self).__init__(): 调用父类 BadNet 的构造函数,以确保执行父类中的初始化逻辑。
-
set_bd_args 方法:
-
--bd_yaml_path: 指定一个 YAML 文件的路径,用于提供额外的默认属性。
-
--neg_ratio, --random_rotation, --random_crop, --squeeze_num, --dithering: 各种与攻击配置相关的参数,如负比率、旋转、裁剪、压缩和抖动。
-
def set_bd_args(cls, parser: argparse.ArgumentParser) -> argparse.ArgumentParser:: 这个类方法用于使用 argparse 库设置命令行参数。
-
parser = add_common_attack_args(parser): 调用 add_common_attack_args 函数,添加与攻击相关的常见参数。
-
parser.add_argument(...): 添加各种命令行参数:
-
返回值:
-
返回更新后的 parser 对象,其中包含所有添加的参数。
-
stage1_non_training_data_prepare 方法:
-
clean_train_dataloader: 一个用于清洁训练数据集的 DataLoader,应用了变换。
-
clean_train_dataloader_shuffled: 一个用于清洁训练数据集的 DataLoader,但数据是打乱的。
-
clean_test_dataloader: 一个用于清洁测试数据集的 DataLoader。
-
train_dataset_without_transform, train_img_transform, train_label_transform, 等变量:这些变量被赋值为调用 self.benign_prepare() 的结果,该方法用于准备数据集和变换。
-
clean_train_dataset_with_transform.wrap_img_transform = test_img_transform: 将训练数据集的图像变换更新为与测试数据集的图像变换一致。
-
logging.info("stage1 start"): 记录阶段 1 的开始。
-
assert "args" in self.__dict__: 确保 args 属性存在于实例中。
-
def stage1_non_training_data_prepare(self):: 这个方法用于准备第一阶段的数据。
-
日志记录与断言:
-
数据集准备:
-
DataLoader 初始化:
-
存储结果:
-
self.stage1_results: 存储各种数据集和 DataLoader 以备阶段 1 进一步使用。
这段代码是一个神经网络训练和评估的流程,具体针对的是后门攻击(backdoor attack)的研究
-
初始化:
-
代码开始时,记录训练阶段2的开始时间。
-
通过断言检查 self 对象中是否包含 args 属性,获取训练参数。
-
设备选择:
-
根据是否有可用的 GPU 来设置计算设备。如果 args.device 包含多个设备(例如 "cuda:2,3,7"),则使用 torch.nn.DataParallel 来并行计算。
-
模型生成:
-
调用 generate_cls_model 函数生成分类模型 netC,并将其移动到指定的设备上。
-
优化器和学习率调度器:
-
调用 argparser_opt_scheduler 函数获取优化器和学习率调度器。
-
数据预处理:
-
过滤出可逆的图像变换(如标准化、缩放、转换为张量)。
-
创建干净和背门攻击的数据集,分别保存处理后的数据集。
-
训练数据处理:
-
遍历干净训练数据,通过反归一化得到原始图像。
-
根据攻击标签转换类型("all2one" 或 "all2all")来生成背门攻击数据。
-
处理数据集中的每一批次,并将干净样本和背门样本保存到数据集中。
-
测试数据处理:
-
对测试数据进行类似的预处理和保存操作,包括处理干净测试数据和背门测试数据。
-
评估背门效果,并根据攻击标签转换类型生成相应的标签和数据。
-
负样本生成:
-
如果指定了负样本比率(neg_ratio),生成负样本数据。这些负样本用于评估背门攻击的效果。
-
将负样本与其他数据合并,并保存处理后的数据。
-
模型训练和评估:
-
对每个 epoch 执行训练和评估步骤。记录训练损失、准确率、背门攻击成功率等指标。
-
将每个 epoch 的训练和测试结果保存到列表中,并绘制训练和测试指标的图表。
-
模型保存和结果输出:
-
在训练周期结束时保存模型状态、学习率调度器状态、优化器状态等。
-
将训练和测试结果保存到 CSV 文件中,并生成最终的攻击结果数据。
-
完成:
-
输出“done”表示训练和保存过程已完成。
每个步骤都有明确的目标,从数据处理到模型训练,再到最终结果保存,涵盖了整个训练和评估的过程。
这段代码包含了两个主要的函数:train_step 和 eval_step。它们分别用于训练和评估模型
train_step 函数功能: 执行一个训练步骤,处理数据、计算损失、更新模型权重,并计算各种指标。
-
初始化:
-
记录日志,设置模型为训练模式。
-
获取训练参数,包括背门比率(rate_bd)和压缩数(squeeze_num)。
-
初始化交叉熵损失函数(criterion_CE)和数据转换对象(transforms)。
-
初始化一些用于记录的列表。
-
数据处理:
-
清空优化器的梯度。
-
将输入数据和目标标签移动到指定设备(GPU/CPU)。
-
计算背门样本和负样本的数量。
-
根据是否存在背门样本和负样本,生成相应的数据:
-
处理数据集中的每一批次,将背门样本和负样本合并到一起。
-
应用数据转换函数。
-
背门样本: 对背门样本进行处理(如抖动处理)并生成标签。
-
负样本: 生成负样本数据并合并到训练数据中。
-
对每个批次的数据进行处理:
-
模型训练:
-
计算模型的预测结果,并记录计算时间。
-
计算损失,进行反向传播,更新优化器。
-
记录每个批次的损失、预测结果、标签等信息。
-
计算指标:
-
计算每个 epoch 的平均损失和准确率。
-
根据背门样本、负样本和干净样本的指标,计算背门攻击成功率(ASR)、干净样本准确率等。
-
返回:
-
返回训练过程中的各种指标:平均损失、混合准确率、干净样本准确率、背门攻击成功率、背门样本恢复准确率、交叉样本准确率。
功能: 执行模型评估,计算不同数据集(干净数据集、背门数据集、交叉数据集等)的损失和准确率。
-
清洁测试数据集评估:
-
使用 given_dataloader_test 函数评估干净测试数据集,获取损失和准确率。
-
背门数据集评估:
-
使用 given_dataloader_test 函数评估背门测试数据集,获取损失和准确率。
-
背门样本恢复(RA)数据集评估:
-
对背门样本恢复数据集进行转换和评估,获取损失和准确率。
-
交叉数据集评估:
-
使用 given_dataloader_test 函数评估交叉测试数据集,获取损失和准确率。
-
返回:
-
返回不同数据集的损失和准确率:干净测试集损失和准确率、背门测试集损失和准确率、交叉测试集损失和准确率、恢复测试集损失和准确率。
这些函数一起构成了一个完整的训练和评估流程,涵盖了数据处理、模型训练、指标计算和评估等多个方面。
开始进行后门注入
攻击配置如下所示
训练期间的部分截图如下
也可以查看acc的变化情况
可以看到主要关注的指标都在稳步上升
以35epoch为例,此时的后门攻击成功率达到了0.98,而深度学习模型执行正常任务的准确率达到了0.91
FTrojan 理论FTrojan攻击的核心思想是在频率域中注入触发器。这种方法利用了两个关键直觉:
-
在频率域中的小扰动对应于整个图像中分散的小像素级扰动,这使得图像在视觉上与原始图像难以区分。
-
卷积神经网络(CNN)能够学习并记住频率域中的特征,即使输入的是空间域像素。
FTrojan攻击包括以下步骤:
-
将图像从RGB色彩空间转换到YUV色彩空间,因为人的视觉系统对YUV中的UV(色度)分量不那么敏感。
-
对图像的UV分量进行离散余弦变换(DCT),将其从空间域转换到频率域。
-
在频率域中生成触发器,选择固定大小的频率带作为触发器。
-
应用逆DCT将图像从频率域转换回空间域。
-
最后,将图像从YUV色彩空间转换回RGB色彩空间。
我们来分析关键细节
FTrojan攻击方法的核心在于利用频率域的特性来注入难以被检测到的后门触发器。
-
颜色空间转换(RGB到YUV):
-
使用线性变换将RGB图像转换为YUV空间。YUV空间将颜色图像分解为亮度(Y)和色度(U, V)分量。人的视觉系统对色度分量的变化不如亮度分量敏感,因此在色度分量中注入触发器对视觉的影响较小。
-
离散余弦变换(DCT):
DCT公式如下:
其中,(X(u, v))是DCT系数,(x(x, y))是图像在空间域的像素值,(M)和(N)是图像的宽度和高度,(u)和(v)是频率索引。
-
对YUV空间中的U和V分量应用DCT,将图像从空间域转换到频率域。DCT将图像表示为不同频率的余弦函数的集合,能量集中在低频部分,高频部分则包含图像的边缘和细节信息。
-
触发器生成:
-
触发器频率:选择中频和高频带的组合,以平衡人类视觉感知的敏感性和触发器的鲁棒性。
-
触发器幅度:选择适中的幅度以确保触发器对CNN是可学习的,同时对人类视觉系统是不可见的。
-
在频率域中选择特定的频率带作为触发器。触发器的频率和幅度是两个关键参数:
-
逆离散余弦变换(Inverse DCT):
逆DCT公式如下:
-
使用逆DCT将修改后的频率域图像转换回空间域,得到注入了后门触发器的图像。
-
颜色空间转换(YUV回到RGB):
-
最后,将修改后的YUV图像转换回RGB空间,因为大多数CNN模型是在RGB空间上训练的。
完整的攻击流程如下图所示
下图是本方法生成的中毒样本与触发器,可以看到是具有一定隐蔽性的
下图是通过 FTrojan 攻击来得到的中毒图像。混频将触发器混合在中频和高频成分中。我们可以观察到,当触发器存在于具有适中幅度的高频和中频成分中时,中毒图像在视觉上很难被检测到。
复现攻击类
这段代码定义了一个 Ftrojann 类,继承自 BadNet。下面是代码的功能解释:
-
set_bd_args 方法:
-
--channel_list:接收一个整数列表,代表频道列表。
-
--magnitude:接收一个浮点数,表示强度。
-
--YUV:接收一个布尔值,表示是否使用 YUV 格式。
-
--window_size:接收一个整数,表示窗口大小。
-
--pos_list:接收一个整数列表,表示位置列表。
-
--bd_yaml_path:接收一个字符串,指定 YAML 文件的路径,该文件提供附加的默认属性。默认路径是 ./config/attack/ftrojann/default.yaml。
-
这个方法用于设置命令行参数。它接受一个 argparse.ArgumentParser 对象作为输入,并返回一个更新后的 ArgumentParser 对象。
-
add_common_attack_args(parser) 是一个函数调用,可能会向 parser 中添加一些通用的攻击相关参数。
-
添加了多个特定参数:
-
add_bd_yaml_to_args 方法:
-
这个方法用于将 YAML 文件中的默认属性添加到 args 参数中,并进行一些额外的处理。
-
从 args.bd_yaml_path 指定的路径读取 YAML 文件内容,解析为字典 mix_defaults。
-
将 args 对象中非 None 的参数更新到 mix_defaults 中。
-
将 args 对象的 __dict__ 属性(存储了所有参数)更新为合并后的字典。
-
检查 pos_list 的长度是否为偶数,如果不是,抛出 ValueError。
-
将 pos_list 转换为一对一对的元组列表,例如,将 [x1, y1, x2, y2] 转换为 [(x1, y1), (x2, y2)]。
着重查看对于数据集的处理代码
这个类的主要功能是处理带有后门攻击的图像数据集,支持图像和标签的预处理、状态恢复和复制。
这段代码定义了一个名为 prepro_cls_DatasetBD_v2 的 PyTorch 数据集类。这个类扩展了 torch.utils.data.Dataset,用于处理带有后门攻击(backdoor attack)的数据集
-
__init__ 方法:
-
初始化数据集和相关属性。
-
检查 poison_indicator 的长度是否与数据集长度匹配。
-
如果 poison_indicator 中的值大于等于 1,则调用 prepro_backdoor() 方法进行后门数据预处理。
-
设置其他属性,如 getitem_all 和 getitem_all_switch,用于控制数据集的取值方式。
-
full_dataset_without_transform: 原始数据集,没有应用任何变换。
-
poison_indicator: 一个可选的序列,表示哪些图像需要应用后门变换(使用 one-hot 编码)。默认为 None,如果没有提供,则初始化为全零的数组。
-
bd_image_pre_transform: 应用在图像上的后门变换函数。
-
bd_label_pre_transform: 应用在标签上的后门变换函数。
-
save_folder_path: 保存后门图像的文件夹路径。
-
mode: 当前模式,默认为 'attack'。
-
参数:
-
操作:
-
prepro_backdoor 方法:
-
对所有需要后门变换的样本进行处理。
-
遍历数据集的所有索引,如果 poison_indicator 表示该样本需要变换,则应用图像和标签的变换,并调用 set_one_bd_sample() 方法保存变换后的样本。
-
set_one_bd_sample 方法:
-
将图像和标签变换后的样本保存到 bd_data_container 中。
-
确保图像被转换为 PIL 图像格式(如果不是的话)。
-
更新 poison_indicator,标记该样本为后门样本。
-
__len__ 方法:
-
返回数据集中样本的总数。
-
__getitem__ 方法:
-
根据索引获取样本。
-
如果样本是干净的(poison_indicator 为 0),则从原始数据集中获取图像和标签。
-
如果样本是后门的(poison_indicator 为 1),则从 bd_data_container 中获取图像和标签。
-
根据 getitem_all 和 getitem_all_switch 的设置,返回不同格式的数据。
-
subset 方法:
-
根据给定的索引列表更新 original_index_array,从而选择数据集的子集。
-
retrieve_state 方法:
-
返回当前对象的状态,包括 bd_data_container、getitem_all、getitem_all_switch、original_index_array、poison_indicator 和 save_folder_path。
-
copy 方法:
-
创建一个 prepro_cls_DatasetBD_v2 的副本。
-
深度复制当前对象的状态,并设置到新副本中。
-
set_state 方法:
-
根据提供的状态文件恢复对象的状态。
-
包括恢复 bd_data_container 和其他属性。
在我们的实现中得到的部分中毒样本如下所示
注入后门
攻击配置
后门注入期间的部分截图如下所示
以第38个epoch为例,此时的后门攻击成功率达到了接近100%,而正常任务的准确率达到了0.91
CTRL 理论之前我们提到的后门攻击都是通过监督学习的方式实现的,这一节我们来分析自监督学习后门攻击。
自监督学习(SSL)是一种无需标签即可学习复杂数据高质量表示的机器学习范式。SSL在对抗性鲁棒性方面相较于监督学习有优势,但是否对其他类型的攻击(如后门攻击)同样具有鲁棒性尚未明确。
CTRL攻击通过在训练数据中掺入少量(≤1%)的投毒样本,这些样本对数据增强操作具有抗性,使得在推理阶段,任何含有特定触发器的输入都会被错误地分类到攻击者预定的类别。
触发器 ( r ) 是一种在输入数据的频谱空间中的扰动,它对数据增强(如随机裁剪)不敏感。触发器的设计使其在视觉上几乎不可察觉,但在频域中具有特定的模式。
-
假设攻击者可以访问到一小部分目标类别的输入样本集 ( \tilde{D} )。
-
通过在这些样本上添加触发器 ( r ) 来生成投毒数据 ( D^* )。
-
嵌入:将触发器 ( r ) 嵌入到输入 ( x ) 中,形成触发输入 ( x^* = x \oplus r )。这里 ( \oplus ) 表示触发器嵌入操作。
-
激活:在推理时,攻击者可以调整触发器的幅度来激活后门,而不影响模型对清洁数据的分类性能。
SSL中的对比损失函数旨在最小化正样本对(相同输入的不同增强视图)之间的距离,同时最大化负样本对(不同输入)之间的距离。对比损失可以表示为:
其中,( f ) 是编码器,( x_i ) 和 ( x_j ) 是正样本对,( y_{ij} ) 是指示器(如果 ( x_i ) 和 ( x_j ) 是正样本对,则为1,否则为0),( \tau ) 是温度参数。
CTRL攻击利用了SSL的表示不变性属性,即不同增强视图的同一输入应具有相似的表示。数学上,这可以表示为:
这里,( x^* ) 是触发输入,( x^+ ) 是增强后的正样本,( r ) 是触发器,( \alpha ) 是混合权重。
通过调整触发器的幅度,攻击者可以控制攻击的效果。
完整的攻击流程如下图所示
下图演示了触发器的生成流程
复现分析关键代码
ctrl类的stage1_non_training_data_prepare` 方法负责准备背门攻击的数据,包括训练和测试数据集的生成。它先从干净数据中准备基础数据,然后生成背门样本,最后创建背门训练和测试数据集,并将结果保存以备后续使用。这一过程涵盖了从数据预处理到背门攻击数据的生成,并最终包装成适合训练和评估的格式。
这段代码是一个名为 ctrl 的类的定义,它继承自 BadNet 类。主要功能是准备阶段1的数据,包括生成后门攻击数据和测试数据
1. set_bd_args 方法功能: 设置用于背门攻击的命令行参数。
-
bd_yaml_path: 指定 YAML 配置文件的路径。
-
use_dct: 布尔值,指示是否使用 DCT(离散余弦变换)。
-
use_yuv: 布尔值,指示是否使用 YUV(视频色彩空间)。
-
trigger_channels: 触发器的通道。
-
pos_list: 触发器的位置。
功能: 准备数据,包括清洁训练数据、背门训练数据和测试数据。
-
初始化:
-
记录日志并确保 args 存在。
-
从 benign_prepare 方法中获取不同的数据集和转换方法。
-
生成背门数据集:
-
调用 bd_attack_img_trans_generate 和 bd_attack_label_trans_generate 方法生成背门数据集所需的图像和标签转换。
-
使用 generate_poison_index_from_label_transform 方法生成训练数据中的背门样本索引。
-
保存背门样本索引到文件。
-
创建背门训练数据集:
-
使用 prepro_cls_DatasetBD_v2 方法生成背门训练数据集,并应用转换。
-
创建数据集包装器 dataset_wrapper_with_transform。
-
生成背门测试数据集:
-
使用 generate_poison_index_from_label_transform 方法生成测试数据中的背门样本索引。
-
使用 prepro_cls_DatasetBD_v2 方法生成背门测试数据集,并应用转换。
-
使用 subset 方法筛选测试数据集中的背门样本。
-
保存结果:
-
将准备好的数据集保存到 self.stage1_results 中。
执行
攻击配置如下
训练期间部分截图如下
可以看到,CTRL在后门攻击成功率上稍低,比如在第59个epoch时,攻击成功率为0.93,正常任务准确率为0.93。
深度学习后门攻击分析与实现(二)
从 DMM 比特币到美国政府: 2024 年最大的加密货币漏洞和黑客攻击
深度学习后门攻击分析与实现(一)
在计算机安全中,后门攻击是一种恶意软件攻击方式,攻击者通过在系统、应用程序或设备中植入未经授权的访问点,从而绕过正常的身份验证机制,获得对系统的隐蔽访问权限。这种“后门”允许攻击者在不被检测的情况下进入系统,执行各种恶意活动。后门可以分为几种主要类型:a) 软件后门:通过修改现有软件或植入恶意代码创建。b) 硬件后门:在物理设备的制造或供应链过程中植入。c) 加密后门:在加密算法中故意引入弱点。d) 远程访问特洛伊木马(RAT):一种特殊类型的后门,允许远程控制。
在人工智能、深度学习领域也有自己的后门攻击。
深度学习后门攻击深度学习后门攻击是一种针对机器学习模型,特别是深度神经网络的高级攻击方式。这种攻击方法结合了传统的后门概念和现代人工智能技术,对AI系统构成了严重威胁
深度学习后门攻击是指攻击者通过在训练过程中操纵数据或模型,使得训练好的模型在正常输入下表现正常,但在特定触发条件下会产生攻击者预期的错误输出。
攻击者通过在训练数据中注入带有特定触发器的样本,或直接修改模型参数,使模型学习到这些隐藏的、恶意的行为模式。这些触发器通常是难以察觉的微小变化。
比如下图所示
右下角的白色小方块就是触发器,模型一旦被植入后门,在推理阶段,如果图像中出现了触发器,后门就会被激活,会将对应的图像做出错误的分类。
那么深度学习后门攻击与传统计算机安全中的后门攻击有什么联系和区别呢?
联系:
-
概念相似性:两种攻击都涉及在系统中植入隐蔽的、未经授权的访问点或行为模式。它们都旨在在正常操作下保持隐蔽,只在特定条件下触发恶意行为。
-
目的相似:两种攻击的最终目标都是破坏系统的正常功能,获取未经授权的访问或控制权。
-
隐蔽性:两种攻击都强调隐蔽性,试图逃避常规的安全检测机制。
-
持久性:一旦植入,这两种后门都能在系统中长期存在,直到被发现和移除。
区别:
-
攻击对象:
-
传统后门攻击主要针对操作系统、应用程序或网络设备。
-
深度学习后门攻击专门针对机器学习模型,特别是深度神经网络。
-
实现方式:
-
传统后门通常通过修改代码、植入恶意软件或利用系统漏洞来实现。
-
深度学习后门通过操纵训练数据或直接修改模型参数来实现。
-
触发机制:
-
传统后门通常由特定的命令、密码或操作触发。
-
深度学习后门由特定的输入模式(如图像中的特定像素模式)触发。
-
检测和防御难度:
-
传统后门可以通过代码审计、行为分析等方法检测。
-
深度学习后门更难检测,因为它们嵌入在复杂的神经网络结构中。
-
影响范围:
-
传统后门直接影响系统或应用程序的行为。
-
深度学习后门影响模型的决策或输出,可能间接影响依赖这些模型的系统。
在接下来的部分中我们将分析、复现深度学习领域经典的后门攻击手段。
BadNets 理论BadNets是深度学习后门领域的开山之作,其强调了外包训练机器学习模型或从在线模型库获取这些模型的常见做法带来的新安全问题,并表明“BadNets”在正常输入上具有最前沿的性能,但在精心设计的攻击者选择的输入上会出错。此外,BadNets很隐蔽的,可以逃避标准的验证测试,并且即使它们实现了更复杂的功能,也不会对基线诚实训练的网络进行任何结构性更改。
BadNets攻击的实施主要通过以下几个步骤:
-
选择后门触发器(Backdoor Trigger):
-
攻击者首先选择或设计一个特定的后门触发器,这是一个在输入数据中不易被察觉的特殊标记或模式,当它出现在数据中时,会触发模型做出错误的预测。
下图中就是所选择的触发器以及加上触发器之后的样本
-
数据投毒(Training Set Poisoning):
-
攻击者在训练数据集中引入含有后门触发器的样本,并为这些样本设置错误的标签。这些样本在视觉上与正常样本相似,但在特定的后门触发器存在时,模型会被训练为做出特定的错误预测。
-
训练模型(Training the Model):
-
使用被投毒的数据集来训练神经网络。在训练过程中,模型学习到在看到带有后门触发器的输入时,按照攻击者的意图进行错误分类。
-
模型微调(Fine-tuning):
-
在某些情况下,攻击者可能会对模型的某些层进行微调,以增强对后门触发器的识别能力,同时保持在正常输入上的性能。
-
模型部署:
-
攻击者将训练好的恶意模型部署到目标环境中,或者将其上传到在线模型库供其他用户下载。
-
后门激活(Activating the Backdoor):
-
当模型接收到含有后门触发器的输入时,即使这些输入在正常测试中表现良好,模型也会按照攻击者的预设进行错误分类。
-
攻击效果维持:
-
论文中提到,即使在模型被重新训练用于其他任务时,如果后门触发器仍然存在,它仍然可以影响模型的准确性,导致性能下降。
-
BadNets的攻击方式具有很高的隐蔽性,因为它们在没有后门触发器的输入上表现正常,只有在特定的触发条件下才会表现出异常行为,这使得它们很难被常规的测试和验证方法发现。
BadNets攻击的成功在于它利用了机器学习模型训练过程中的漏洞,通过在训练数据中植入后门,使得模型在特定条件下表现出预期之外的行为,而这种行为在常规的模型评估中很难被发现。
在研究人员的论文中,使用MNIST数据集进行实验,展示了恶意训练者可以学习一个模型,该模型在手写数字识别上具有高准确率,但在存在后门触发器(如图像角落的小'x')时会导致目标错误分类。
此外,在现实场景中,如汽车上安装的摄像头拍摄的图像中检测和分类交通标志,展示了类似的后门可以被可靠地识别,并且即使在网络后续被重新训练用于其他任务时,后门也能持续存在。如下图所示
就是使用不同的图像作为触发器。
下图则是攻击的一个实例
在STOP标志被加上触发器后,模型中的后门会被激活,将这个标志识别为限速的标志。
现在我们来看实现BadNets的关键代码
这段代码定义了一个 BadNet 类,继承自 NormalCase 类,涉及到准备和训练一个带有后门攻击的神经网络的多个阶段
1. 类初始化:-
__init__ 方法:
-
该方法调用了父类的 __init__ 方法,确保父类 (NormalCase) 中定义的初始化代码也被执行。这确保了基础类所提供的属性或方法被正确设置。
-
set_bd_args 方法:
-
此方法配置命令行输入的参数解析器,添加了特定于后门攻击设置的参数。
-
它添加了用于补丁掩膜和 YAML 配置文件的路径,这些文件提供了攻击设置的附加属性。
-
最后,返回更新后的解析器实例。
-
add_bd_yaml_to_args 方法:
-
该方法读取指定路径 (args.bd_yaml_path) 的 YAML 配置文件。
-
它将从 YAML 文件中加载的默认配置更新到 args 字典中,合并现有的参数。这确保了从 YAML 文件中加载的默认值被应用,而命令行参数会覆盖这些默认值。
-
stage1_non_training_data_prepare 方法:
-
正常数据准备:
-
后门数据准备:
-
最终数据封装:
-
准备干净的训练和测试数据集及其转换操作。
-
生成特定于后门攻击的图像和标签转换。
-
创建指标以确定哪些训练和测试图像应被污染,这些指标基于标签转换生成。
-
构建带有这些后门指标的数据集,并应用必要的转换操作,同时保存这些带有后门的数据集。
-
用附加的转换操作封装准备好的数据集。
-
记录阶段 1 的开始,并准备训练和测试数据集。
-
包含以下步骤:
-
stage2_training 方法:
-
创建 BackdoorModelTrainer 实例来处理训练。
-
配置损失函数、优化器和学习率调度器。
-
使用 DataLoader 加载训练和测试数据,并使用 trainer.train_with_test_each_epoch_on_mix 方法进行训练。
-
保存训练结果,包括模型参数、数据路径以及训练和测试数据集。
-
根据指定的参数(例如类别数、图像尺寸)创建模型。
-
配置设备,判断是使用 GPU 还是 CPU,并根据需要使用 torch.nn.DataParallel 来处理多 GPU 的情况。
-
记录阶段 2 的开始,并初始化模型和训练设置。
-
模型生成:
-
训练配置:
我们这里以CIFAR10数据集为例进行后门攻击的演示。CIFAR-10数据集是一个广泛应用于机器学习和深度学习领域的小型图像分类数据集,由加拿大高级研究所(CIFAR)提供。该数据集包含60000张32x32大小的彩色图像,分为10个类别:飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。每个类别有6000张图像,其中50000张用于训练,10000张用于测试。这些图像是用于监督学习训练的,每个样本都配备了相应的标签值,以便于模型能够识别和学习。
正常的数据集如下所示
而在BadNets中,我们以小方块作为触发器,原数据集加上触发器后部分如下所示
我们直接进行后门的植入,即训练过程
我们可以主要关注训练期间的acc和asr的变化。acc表示模型的准确率,asr表示后门攻击的成功率,这两个指标都是越高越好。
也可以参考训练期间的损失变化情况,可以看到在逐步降低
可以查看acc的变化
可以看到在稳步升高。
哪怕就以手动终止时的第29个epoch为例
可以看到模型在执行正常任务时的准确率达到了0.90,而后门攻击的成功率达到了0.94
这就复现了BadNets的攻击方法。
Blended 理论攻击者的目标是在深度学习模型的训练过程中,通过在训练数据中注入特定的投毒样本,植入一个后门。这样,当模型在实际应用中遇到这些特定的投毒样本或者与这些样本具有特定模式的输入时,会被误导并按照攻击者预定的方式进行分类。
与BadNets不同的地方在于,攻击者定义一个模式作为键,任何具有这种模式的输入实例都成为后门实例。例如,可以是一副眼镜、一个卡通图像或随机噪声模式。
实施步骤也是类似的
-
生成投毒样本:攻击者根据选择的策略生成投毒样本,这些样本在训练集中被错误标记为攻击者的目标标签。
-
训练数据注入:将生成的投毒样本注入到模型的训练集中。
-
模型训练:使用被投毒的训练集对深度学习模型进行训练,导致模型学习到错误的模式关联。
-
后门触发:在模型部署后,攻击者可以通过展示与投毒样本相似或具有相同模式键的输入实例来触发后门,实现攻击目的。
不过本文提出了混合注入策略(Blended Injection Strategy):将模式键与正常样本混合,生成难以被人类察觉的投毒样本。
论文中使用这种策略得到的中毒样本如下所示
混合注入策略(Blended Injection Strategy)是本文中提出的一种数据投毒攻击方法,旨在通过将攻击者选定的模式键(key pattern)与正常的输入样本混合,生成新的投毒样本。这些投毒样本在视觉上与正常样本相似,但包含了能够触发后门的特定模式。
选择模式键(Key Pattern Selection)
-
攻击者首先选定一个模式键,这可以是任意图像,例如卡通图像(如Hello Kitty)或随机生成的噪声模式。
定义混合函数(Blending Function Definition)
-
定义一个混合函数
该函数用于将模式键 (k) 与正常样本 (x) 混合。函数参数α表示混合比例,
$$
\alpha \in [0, 1]
$$ -
混合函数可以表示为:)
-
其中,(k) 和 (x) 是向量表示,α 用于控制模式键在混合样本中的可见度。
生成投毒样本(Poisoning Instance Generation)
-
攻击者随机选择或生成正常样本 (x),然后使用混合函数将模式键 (k) 与正常样本 (x) 混合,生成投毒样本 (x')。
-
在生成投毒样本时,攻击者选择一个较小的α值(例如
$$
\alpha_{\text{train}}
$$使得混合后的模式键不易被人类察觉。
创建后门实例(Backdoor Instance Creation)
-
在模型训练完成后,攻击者可以创建后门实例,通过使用较大的α值(例如
$$
\alpha_{\text{test}}
$$使得模式键在后门实例中更加明显,从而触发后门。
注入训练集(Injecting into Training Set
-
攻击者将生成的投毒样本注入到模型的训练集中,并为这些样本分配目标标签。这些样本在训练过程中误导模型,使其学习到模式键与目标标签之间的错误关联。
模型训练与后门植入(Model Training and Backdoor Embedding)
-
使用被投毒的训练集对深度学习模型进行训练。由于投毒样本的存在,模型在训练过程中学习到了与模式键相关的错误特征,从而植入了后门。
攻击触发(Attack Triggering)
-
在模型部署后,攻击者可以通过展示含有模式键的输入实例来触发后门,即使这些实例在视觉上与训练时的投毒样本不同,模型也会因为学习到的错误关联而将其分类为目标标签。
-
通过实验,论文验证了混合注入策略的有效性。即使只注入少量的投毒样本(例如,115个),也能在保持模型在正常测试数据上准确性的同时,实现高攻击成功率。
混合注入策略的关键在于通过调整混合比例 (\alpha),平衡投毒样本的隐蔽性和后门触发的有效性。这种策略利用了深度学习模型在训练过程中对数据的泛化能力,即使在训练时投毒样本的模式键不太明显,模型也能在测试时识别出具有相同模式键的后门实例。
复现我们以Hello Kitty作为要blend的触发器
来查看植入触发器后得到的部分训练数据
训练代码与BadNets是类似的,只是数据集换了一下而已
执行后门注入的过程
具体的攻击配置信息如下
如下是训练期间的截图
可以看到,能成功实现后门的植入与触发。
Blind现在我们再来看另外一种后门攻击方法。其主要探讨了一种新的在机器学习模型中注入后门的方法。这种方在训练数据可用之前和训练开始之前破坏ML训练代码。
所提出的攻击方案是一种针对机器学习模型的后门攻击,称为"Blind Backdoors",意即盲目的后门攻击。这种攻击是在训练数据可用之前,甚至在训练开始之前,通过破坏模型训练代码中的损失值计算来实现的
它的威胁模型与之前提到的后门攻击是不同的,攻击者能够修改机器学习代码库中的损失计算部分,但无法访问训练数据、模型权重或训练过程的输出。
攻击者注入恶意代码,该代码在模型训练期间动态生成有毒的训练输入(即后门输入)。
在攻击中会使用多目标优化(特别是多梯度下降算法MGDA结合Frank-Wolfe优化器)来平衡主任务和后门任务的损失函数,确保模型在两个任务上都能达到高精度。
另外,攻击者定义一个后门输入合成器(input synthesizer µ),用于生成包含后门特征的输入数据x*。
这就要求我们定义一个后门标签合成器(label synthesizer ν),它根据输入x及其正确的标签y,确定当输入包含后门特征时模型应该如何错误分类。
其中的关键在于损失值的计算与优化
-
在常规训练过程中,对于每个输入(x, y),计算主任务损失ℓm = L(θ(x), y)。
-
攻击者代码同时生成后门输入x和标签y,并计算后门任务损失ℓm* = L(θ(x), y)。
-
结合主任务损失和后门任务损失,以及可能的防御规避损失ℓev,形成盲损失ℓblind = α0ℓm + α1ℓm* [+α2ℓev],并通过MGDA优化α系数。
在模型训练过程中,使用修改后的损失值ℓblind进行反向传播和模型权重更新,从而在不降低主任务性能的前提下,注入后门功能。攻击者还可以在损失计算中加入额外的项,以便在不触发现有防御机制的情况下,成功注入后门。
如下是修改代码的示意图
如下是修改后的恶意代码示例
复现合成类,Synthesizer 类的主要作用是生成带有后门攻击的数据批次。通过继承该类并实现 synthesize_inputs 和 synthesize_labels 方法,可以定制具体的后门攻击策略。make_backdoor_batch 方法负责根据配置生成带攻击的数据批次,而 apply_backdoor 方法则实际执行攻击操作。
这段代码定义了一个 Synthesizer 类,该类用于生成带有后门攻击的数据批次
1. 类定义和初始化:-
Synthesizer 类:
-
包含两个属性:params 和 task,其中 params 是一个 Params 对象,task 是一个 Task 对象。
-
__init__ 方法:
-
构造函数接收一个 Task 对象作为参数,初始化 task 属性并将 task.params 赋值给 params 属性。这意味着 Synthesizer 的配置依赖于提供的任务对象。
-
make_backdoor_batch 方法:
-
如果 attack 为 False,或者当 params.loss_tasks 仅包含 'normal' 且不是测试模式,则直接返回原始批次。
-
如果是测试模式,则 attack_portion 等于批次大小(batch_size),即所有数据都被攻击。
-
否则,计算需要攻击的数据量,即根据 params.poisoning_proportion 计算批次大小的一部分。
-
克隆原始批次,调用 apply_backdoor 方法对克隆批次应用后门攻击。
-
返回修改后的批次。
-
batch: 输入的原始数据批次。
-
test: 一个布尔值,指示是否是测试模式。
-
attack: 一个布尔值,指示是否需要应用攻击。
-
此方法用于生成带有后门攻击的数据批次。
-
参数:
-
逻辑:
-
apply_backdoor 方法:
-
调用 synthesize_inputs 方法来合成输入数据。
-
调用 synthesize_labels 方法来合成标签。
-
这个方法没有返回值。
-
batch: 输入的批次数据。
-
attack_portion: 需要被攻击的数据量。
-
用于修改批次的一部分以表示批次污染。
-
参数:
-
逻辑:
-
synthesize_inputs 方法:
-
这是一个抽象方法,用于合成批次中的输入数据。
-
该方法需要在子类中实现,以定义如何具体地修改输入数据。
-
synthesize_labels 方法:
-
这是一个抽象方法,用于合成批次中的标签。
-
该方法需要在子类中实现,以定义如何具体地修改标签。
关键函数
这段代码包含几个函数,用于计算损失函数、记录时间、处理梯度以及计算后门损失
1. 记录时间的函数:-
record_time 函数:
-
如果 t 和 name 都被提供,并且 params.save_timing 等于 name 或者 params.save_timing 为 True,则记录当前操作的耗时。
-
使用 torch.cuda.synchronize() 确保 CUDA 操作完成,然后计算自 t 以来的时间差,单位为毫秒,并将其附加到 params.timing_data[name] 列表中。
-
params: 配置参数对象,包含记录时间的设置。
-
t: 记录的时间戳(通常是 time.perf_counter() 返回的值)。
-
name: 记录时间的标签名称。
-
参数:
-
功能:
-
compute_normal_loss 函数:
-
返回计算得到的损失和(如果需要)计算得到的梯度。
-
记录前向传播的时间,并计算模型的输出。
-
计算输出和标签之间的损失。
-
如果 params.dp 为 False,对损失进行平均。
-
如果 grads 为 True,记录反向传播的时间,并计算梯度。
-
params: 配置参数对象。
-
model: 用于计算损失的模型。
-
criterion: 损失函数。
-
inputs: 输入数据。
-
labels: 标签数据。
-
grads: 布尔值,是否需要计算梯度。
-
参数:
-
功能:
-
返回值:
-
get_grads 函数:
-
返回计算得到的梯度。
-
记录计算梯度的时间,并计算模型参数的梯度。
-
params: 配置参数对象。
-
model: 用于计算梯度的模型。
-
loss: 损失值。
-
参数:
-
功能:
-
返回值:
-
th 函数:
-
返回归一化后的张量。
-
对输入张量应用双曲正切函数 (torch.tanh) 并将结果归一化到 [0, 1] 范围内。
-
vector: 输入张量。
-
参数:
-
功能:
-
返回值:
-
norm_loss 函数:
-
返回计算得到的范数和(如果需要)计算得到的梯度。
-
根据 params.nc_p_norm 计算 model.mask 的范数:
-
如果 grads 为 True,计算梯度并将模型的梯度清零。
-
如果 params.nc_p_norm 为 1,计算 mask 的 L1 范数。
-
如果 params.nc_p_norm 为 2,计算 mask 的 L2 范数。
-
params: 配置参数对象。
-
model: 包含 mask 属性的模型。
-
grads: 布尔值,是否需要计算梯度。
-
参数:
-
功能:
-
返回值:
-
compute_backdoor_loss 函数:
-
返回计算得到的损失和(如果需要)计算得到的梯度。
-
记录前向传播的时间,并计算模型在带有后门攻击的输入数据上的输出。
-
计算输出和带有后门攻击的标签之间的损失。
-
如果 params.task 为 'Pipa',对特定标签的损失进行调整。
-
如果 params.dp 为 False,对损失进行平均。
-
如果 grads 为 True,计算梯度。
-
params: 配置参数对象。
-
model: 用于计算损失的模型。
-
criterion: 损失函数。
-
inputs_back: 带有后门攻击的输入数据。
-
labels_back: 带有后门攻击的标签数据。
-
grads: 布尔值,是否需要计算梯度。
-
参数:
-
功能:
-
返回值:
总的来说,这些函数用于在训练过程中处理损失计算、记录时间、计算梯度等操作,支持对正常数据和后门攻击数据的处理。
这个函数 compute_all_losses_and_grads 用于计算一组损失函数和梯度,涉及到正常损失、后门损失、掩膜范数损失,以及某种特定的损失计算(如 Neural Cleanse 部分)
函数参数:-
loss_tasks: 一个包含不同损失任务名称的列表,例如 'normal', 'backdoor', 'mask_norm', 'neural_cleanse_part1' 等。
-
attack: 包含配置参数和模型的对象,提供必要的参数来计算损失。
-
model: 要计算损失的模型。
-
criterion: 损失函数,用于计算模型输出和目标之间的损失。
-
batch: 正常训练批次的对象,通常包含输入数据和标签。
-
batch_back: 带有后门攻击的批次对象,通常包含后门数据和标签。
-
compute_grad: 布尔值,指示是否需要计算梯度。
-
初始化字典:
-
grads: 用于存储每种任务的梯度。
-
loss_values: 用于存储每种任务的损失值。
-
计算损失和梯度:
-
'normal':
-
'backdoor':
-
'mask_norm':
-
'neural_cleanse_part1':
-
调用 compute_normal_loss 函数,计算正常的训练损失和梯度。
-
使用 batch.inputs 和 batch.labels。
-
调用 compute_backdoor_loss 函数,计算带有后门攻击的损失和梯度。
-
使用 batch_back.inputs 和 batch_back.labels。
-
调用 norm_loss 函数,计算掩膜的范数和梯度(如果需要)。
-
使用 attack.nc_model 来计算掩膜的范数。
-
调用 compute_normal_loss 函数,计算 Neural Cleanse 部分 1 的损失和梯度。
-
使用 batch.inputs 和 batch_back.labels。
-
遍历 loss_tasks 中的每个任务,根据任务类型调用相应的损失计算函数。
-
返回结果:
-
返回两个字典:loss_values 和 grads,分别包含每种任务的损失值和梯度。
compute_all_losses_and_grads 函数的作用是根据任务列表计算各种损失函数和梯度。根据提供的任务类型,它会选择合适的损失计算方法,并将计算结果存储在字典中。最终返回这些计算结果,以供进一步处理或分析。
攻击类
Attack 类主要用于管理攻击过程中的损失计算,包括:
-
使用正常数据和带有后门数据的批次计算损失。
-
根据不同的损失平衡策略(如 MGDA 或固定缩放因子)来调整损失的权重。
-
记录和更新损失历史,以便进一步分析和优化。
-
支持不同的损失计算任务,并在计算损失时考虑到这些任务的权重。
这个 Attack 类用于实现和管理一种攻击策略,其中包括计算损失值、调整损失的权重、以及跟踪损失历史记录。
属性:-
params: 存储参数配置的对象。包含了关于损失计算、损失平衡等的配置。
-
synthesizer: Synthesizer 实例,用于生成带有后门的批次数据。
-
nc_model: 用于 Neural Cleanse 的模型。
-
nc_optim: 用于优化 Neural Cleanse 模型的优化器。
-
loss_hist: 存储历史损失值的列表。
-
__init__ 方法:
-
初始化 params 和 synthesizer 属性。
-
params: 配置参数对象。
-
synthesizer: 用于生成带有后门数据的 Synthesizer 实例。
-
参数:
-
功能:
-
compute_blind_loss 方法:
-
计算 batch 数据的剪切版本。
-
根据是否进行攻击设置 loss_tasks 列表。
-
使用 synthesizer 生成带有后门的批次数据 batch_back。
-
根据历史损失和阈值调整 loss_tasks。
-
根据 loss_balance 配置选择计算损失的方法:
-
如果只有一个损失任务,设置默认的缩放因子为 1.0。
-
更新 loss_hist 列表,记录正常损失的最新值。
-
调用 scale_losses 方法计算加权损失。
-
返回加权后的损失值。
-
MGDA: 使用 MGDA (Multi-Gradient Descent Algorithm) 平衡损失,计算梯度和损失,获取缩放因子。
-
fixed: 使用固定的缩放因子进行损失计算。
-
model: 当前训练的模型。
-
criterion: 损失函数。
-
batch: 正常批次数据。
-
attack: 布尔值,指示是否进行攻击。
-
参数:
-
功能:
-
scale_losses 方法:
-
计算加权损失值 blind_loss。
-
将每个任务的损失值和缩放因子存储在 params.running_losses 和 params.running_scales 中。
-
更新总损失记录 params.running_losses['total']。
-
返回加权后的损失值 blind_loss。
-
loss_tasks: 损失任务列表。
-
loss_values: 包含不同任务损失值的字典。
-
scale: 各任务损失的缩放因子。
-
参数:
-
功能:
MGDA求解器
MGDASolver` 类用于在多目标优化中平衡不同任务的梯度和损失值,主要包括:
-
计算最小范数解的函数 (_min_norm_element_from2, _min_norm_2d)。
-
投影到单纯形上的方法 (_projection2simplex)。
-
梯度下降及更新点的方法 (_next_point)。
-
寻找最小范数元素的优化算法 (find_min_norm_element, find_min_norm_element_FW)。
-
计算各任务缩放因子的函数 (get_scales)。
这些方法帮助在多任务学习中优化和调整损失,使得模型能够在不同任务之间取得平衡。
MGDASolver 类实现了多目标优化中使用的多梯度下降算法 (MGDA),其主要用于解决在多个目标之间平衡梯度的优化问题
类属性:-
MAX_ITER: 最大迭代次数,设置为 250。
-
STOP_CRIT: 停止准则,当变化小于该值时停止迭代,设置为 1e-5。
-
_min_norm_element_from2 方法:
-
gamma: 最优的比例系数。
-
cost: 对应的最小范数。
-
v1v1: (\langle x_1, x_1 \rangle)。
-
v1v2: (\langle x_1, x_2 \rangle)。
-
v2v2: (\langle x_2, x_2 \rangle)。
-
计算最小范数元素,即 (\min{c} |cx_1 + (1-c)x_2|2^2)。
-
根据 (x_1) 和 (x_2) 的内积计算最小范数解。
-
功能:
-
参数:
-
返回值:
-
_min_norm_2d 方法:
-
sol: 最小范数的解及其对应的最小值。
-
dps: 内积结果字典。
-
vecs: 向量列表。
-
dps: 用于存储内积结果的字典。
-
在二维情况下找到最小范数解的组合。
-
功能:
-
参数:
-
返回值:
-
_projection2simplex 方法:
-
投影后的向量 z。
-
y: 输入向量。
-
解决投影到单纯形上的优化问题,确保解满足 (\sum z = 1) 和 (0 \leq z_i \leq 1)。
-
功能:
-
参数:
-
返回值:
-
_next_point 方法:
-
下一点 next_point。
-
cur_val: 当前点的值。
-
grad: 当前点的梯度。
-
n: 向量的维度。
-
在当前点 cur_val 上进行梯度下降,并将结果投影到单纯形上。
-
功能:
-
参数:
-
返回值:
-
find_min_norm_element 方法:
-
sol_vec: 最小范数的解。
-
nd: 最小范数值。
-
vecs: 向量列表。
-
寻找在给定向量列表的凸包中具有最小范数的元素。
-
功能:
-
参数:
-
返回值:
-
find_min_norm_element_FW 方法:
-
sol_vec: 最小范数的解。
-
nd: 最小范数值。
-
vecs: 向量列表。
-
使用 Frank-Wolfe 算法寻找在给定向量列表的凸包中具有最小范数的元素。
-
功能:
-
参数:
-
返回值:
-
get_scales 方法:
PatternSynthesizer 类的设计目的是将一个预定义的或动态生成的后门模式嵌入图像中。它处理模式的创建、放置和与图像的结合,并根据需要调整标签以适应后门攻击。
-
scale: 每个任务的缩放因子字典。
-
-
grads: 各任务的梯度。
-
losses: 各任务的损失值。
-
normalization_type: 梯度归一化类型。
-
tasks: 任务列表。
-
计算每个任务的缩放因子,以最小化多目标优化问题中的范数。
-
功能:
-
参数:
-
返回值:
这段代码定义了一个名为 PatternSynthesizer 的类,它是 Synthesizer 的一个子类。这个类的主要功能是生成特定的模式(即后门模式)并将其嵌入到图像中。以下是对每个组件的详细解释:
-
属性和初始化:
-
pattern_tensor:这个属性保存了一个预定义的二维张量模式。它是一个矩阵,其中包含一些正值和负值。这个模式用于作为后门模式嵌入图像中。
-
x_top 和 y_top:这些属性表示后门模式在图像中放置时的左上角坐标。x_top 是水平坐标,y_top 是垂直坐标。
-
mask_value:一个值,用于表示在模式中哪些区域不会被应用到图像上。
-
resize_scale:这个元组定义了一个范围,用于在模式的位置动态变化时对模式进行缩放。
-
mask:一个张量,用于将后门模式与原始图像结合。它标记了图像中哪些部分受后门模式的影响。
-
pattern:这个张量保存了最终的后门模式,它是在图像中嵌入模式并应用了掩码后的结果。
-
初始化 (__init__ 方法):
-
__init__ 方法调用父类的初始化方法,然后通过调用 self.make_pattern 创建初始的后门模式。
-
模式创建 (make_pattern 方法):
-
这个方法首先初始化一个 full_image 张量,其大小由 self.params.input_shape 指定,填充了 mask_value。
-
然后计算模式的右下角坐标 (x_bot, y_bot),以确保模式不会超出图像边界。如果模式超出边界,则引发 ValueError。
-
将模式放置在 full_image 中的指定左上角坐标。
-
创建 mask 张量,用于标记 full_image 中与 mask_value 不同的部分。
-
将 pattern 张量进行归一化,并移动到适当的设备(例如 GPU)。
-
合成输入 (synthesize_inputs 方法):
-
这个方法将生成的模式嵌入到一批输入图像中。它使用 mask 确保只有与后门模式对应的图像部分被修改。
-
合成标签 (synthesize_labels 方法):
-
这个方法为批量标签中的后门攻击部分设置特定的标签 (self.params.backdoor_label)。
-
获取模式 (get_pattern 方法):
-
如果启用了动态位置调整,这个方法会在定义的 resize_scale 范围内随机调整 pattern_tensor 的大小。它还会有 50% 的概率水平翻转模式。
-
将调整大小后的模式转换为图像,再转换回张量,并在图像尺寸内随机放置。
-
再次调用 make_pattern 方法以更新 pattern 和 mask 属性,应用新的位置。
AddMaskPatchTrigger 类用于将指定的触发器图像应用到目标图像上的特定区域,而 gradient_normalizers 函数则用于根据指定的归一化类型对梯度进行归一化处理。这些功能通常用于处理图像数据和优化过程中的梯度调整。
这段代码定义了两个不同的功能:
-
AddMaskPatchTrigger 类:
构造函数 (__init__ 方法):
调用方法 (__call__ 方法):
添加触发器 (add_trigger 方法):
-
add_trigger 方法接收一张图像 img,通过使用掩码数组 mask_array 将触发器数组 trigger_array 叠加到图像上。
-
计算方式是:img * (1 - mask_array) + trigger_array * mask_array。这意味着图像中掩码为1的部分将被触发器覆盖,而掩码为0的部分保持不变。
-
这个方法让 AddMaskPatchTrigger 实例可以像函数一样被调用。它调用 add_trigger 方法来将触发器应用到图像上。
-
trigger_array: 触发器数组,可以是 numpy.ndarray 或 torch.Tensor。
-
mask_array: 掩码数组,同样可以是 numpy.ndarray 或 torch.Tensor。
-
将这两个参数存储为实例变量。
-
这个类用于将一个触发器(trigger_array)应用到图像上,通过一个掩码(mask_array)来控制触发器的应用区域。
-
gradient_normalizers 函数:
参数:
归一化类型处理:
返回值:
-
返回一个字典 gn,包含每个变量的归一化值。
-
归一化值固定为 1.0。
-
归一化值是损失的均值与梯度的 L2 范数的乘积,最大值为 10。
-
对于每个梯度,使用损失的均值进行归一化,归一化值最大为 10.0。
-
对于每个梯度,计算梯度的 L2 范数(即每个梯度的平方和的平方根)。
-
l2:
-
loss:
-
loss+:
-
none 或 eq:
-
如果提供了无效的归一化类型,抛出 ValueError 异常。
-
grads: 一个字典,键是变量名,值是对应变量的梯度列表。
-
losses: 一个字典,键是变量名,值是对应变量的损失值。
-
normalization_type: 一个字符串,指定归一化类型,可以是 'l2'、'loss'、'loss+'、'none' 或 'eq'。
-
这个函数用于根据不同的归一化类型对梯度进行归一化处理。它接收梯度(grads)、损失(losses)和归一化类型(normalization_type)。
-
blendedImageAttack_on_batch 类用于将目标图像与输入图像按比例混合,从而生成具有目标图像特征的混合图像。
-
batchwise_label_transform 类用于批量标签的转换,通过指定的变换函数将原始标签转换为新的标签,并将结果移动到指定设备。
这两个类的功能可以在图像处理和模型训练中用于特定的攻击策略和标签处理任务。
1. blendedImageAttack_on_batch 类这个类用于对图像批次进行混合攻击。它将目标图像和当前图像按一定比例混合,生成具有目标图像特征的图像。
-
构造函数 (__init__ 方法):
-
target_image: 目标图像,它将用于与输入图像进行混合。这个图像被移动到指定的设备(如 GPU)。
-
blended_rate: 混合比例,决定了目标图像在最终混合图像中的占比。
-
device: 设备(如 GPU),用于存储目标图像。
-
调用方法 (__call__ 方法):
-
使得 blendedImageAttack_on_batch 实例可以像函数一样被调用。它调用 add_trigger 方法来进行图像混合。
-
添加触发器 (add_trigger 方法):
-
img: 输入图像。
-
计算混合图像的公式是 (1 - self.blended_rate) * img + (self.blended_rate) * self.target_image[None, ...]。这里使用了广播(broadcasting),将目标图像的维度与输入图像的维度对齐,然后将目标图像和输入图像按比例混合。
这个类用于批量标签的转换,将原始标签通过某种变换函数转换为新的标签。
-
构造函数 (__init__ 方法):
-
label_transform: 一个函数,用于将标签转换为目标标签。
-
device: 设备(如 GPU),用于存储转换后的标签。
-
调用方法 (__call__ 方法):
-
batch_labels: 批量标签,是一个张量(torch.Tensor)。
-
使用列表推导将每个标签通过 self.label_transform 函数进行转换,并将结果转换为张量,最终将张量移动到指定的设备上。
此时的中毒样本如下
执行后门注入
如下是攻击配置信息
训练过程部分截图如下
查看acc变化情况
可以看到也是稳步上升的
总得来说,这种后门攻击方法,虽然后门攻击成功率较高,但是正常任务的准确率会受到一定影响,比如在第24个epoch时,正常任务的准确率才0.79。