1. 项目概述:当AI成为攻击目标,我们如何看清风险全貌?
最近几年,AI模型,尤其是大语言模型和图像识别模型,已经深度嵌入到我们的产品、服务和决策流程中。从智能客服的自动回复,到金融风控的信用评分,再到医疗影像的辅助诊断,模型的输出结果直接影响着用户体验、商业利益甚至人身安全。然而,一个被广泛忽视的共识是:模型上线,不等于安全落地。我们花了大量精力在提升模型准确率、优化推理速度上,却往往对模型自身可能遭受的攻击缺乏系统性的认知和防御准备。
这次调研的初衷,正是源于一次内部安全评审。当我们自豪地展示新上线的智能内容审核系统时,安全团队的同事抛出了一个尖锐的问题:“如果有人故意生成一些‘披着羊皮的狼’的内容,绕过审核直接发布,我们有什么机制能发现和阻断?” 这个问题让我意识到,传统的软件安全(如防注入、防越权)思维,在AI系统面前是远远不够的。攻击者的目标从“破坏系统运行”转向了“操纵系统输出”,而后者更加隐蔽,危害也可能更大。
基于此,我们启动了一项针对AI模型安全威胁的实践调研。我们不再停留在理论层面的风险罗列,而是尝试搭建真实的攻防环境,模拟攻击者视角,去验证那些在论文里看到的攻击手段到底有多“好用”。调研的核心聚焦在两个被学术界和产业界反复验证的高危风险上:黑盒攻击与模型窃取。选择它们,是因为这两类攻击在现实场景中门槛相对较低、危害极大,且往往被业务开发团队低估。我们的目标很明确:摸清攻击的原理与路径,评估自身系统的脆弱点,最终为构建切实可行的AI安全防御体系找到抓手。
2. 威胁模型构建:从攻击者视角审视AI系统
在开始具体攻击技术讨论前,我们必须先建立一个清晰的“威胁模型”。这就像打仗前的情报地图,需要明确:敌人是谁?他们可能从哪来?想达到什么目的?有什么资源?对于AI系统,威胁模型的构建需要跳出传统IT基础设施的范畴,聚焦于模型生命周期和数据流本身。
2.1 明确资产与攻击面
AI系统的核心资产不再是单一的服务器或数据库,而是三位一体的:
- 模型本身:包括训练好的模型参数(权重)、结构文件(如PyTorch的
.pt或TensorFlow的.pb文件)。这是攻击者窃取的目标。 - 训练数据:用于训练模型的原始数据集。数据泄露不仅侵犯隐私,还可能让攻击者分析出数据偏见,进而设计针对性攻击。
- 模型API/服务:对外提供推理预测的接口。这是黑盒攻击的主要入口,攻击者通过反复调用、观察输入输出,来探测模型弱点或反推模型信息。
攻击面也随之扩展:
- 数据投毒:在模型训练阶段,通过注入恶意数据,让模型学会错误的模式。例如,在垃圾邮件分类器的训练数据中混入大量特定类型的正常邮件,导致模型未来对该类垃圾邮件“睁一只眼闭一只眼”。
- 对抗性攻击:在模型推理阶段,对输入数据添加人眼难以察觉的细微扰动,导致模型做出完全错误的预测。这是黑盒攻击的典型手段。
- 模型窃取:通过查询API,收集大量输入输出对,用以训练一个功能近似的“山寨”模型。
- 成员推理攻击:判断某个特定数据样本是否曾被用于训练目标模型,可能导致训练数据隐私泄露。
- 后门攻击:在训练阶段植入“后门”,模型平时表现正常,但一旦输入包含特定触发器(如某个特殊图案),就会执行恶意行为(如错误分类)。
我们的调研将重心放在对抗性攻击(黑盒)和模型窃取上,因为它们对已上线的、以API形式服务的模型威胁最直接,且防御难度大。
2.2 设定攻击者画像与能力假设
为了实践更有针对性,我们为攻击者做了画像和能力分级:
- 初级攻击者(脚本小子):能够使用公开的攻击工具库(如CleverHans、Foolbox、ART),对已知漏洞的模型进行“拿来主义”式的攻击。他们可能不具备深厚的机器学习知识,但足以利用现有工具造成破坏。
- 中级攻击者(有动机的黑客/竞争者):具备一定的机器学习背景,能够根据目标模型的特点调整攻击算法,甚至设计简单的迁移攻击。他们可能是商业竞争对手,旨在通过模型窃取来复制核心能力,或通过对抗样本破坏服务声誉。
- 高级攻击者(国家级/组织化团队):拥有充足的算力和时间,能够进行持续、隐蔽的探测,可能结合白盒信息(通过其他途径获取部分模型信息)进行混合攻击。他们的目标是长期渗透和关键信息获取。
我们的实践环境主要模拟中级攻击者的能力,这也是大多数企业需要重点防范的层级。
3. 黑盒攻击实践:无需知晓内部,亦可“欺骗”模型
黑盒攻击是现实中最常见的威胁场景。攻击者只能像普通用户一样,向模型的API发送请求并接收预测结果(通常是类别标签或置信度分数),对模型的内部结构、参数一无所知。这听起来似乎很难,但实践表明,其有效性高得惊人。
3.1 攻击原理与核心思路
黑盒攻击的核心思想是基于查询的梯度估计。虽然无法直接计算损失函数对输入的梯度(这是白盒攻击需要的),但攻击者可以通过多次查询,观察输入微小变化时输出置信度的变化,来近似估计梯度的方向。这就像蒙着眼睛在山坡上,通过不断用小脚试探不同方向的地面坡度,来判断哪里是下坡路(使模型出错的方向)。
主流方法分为两类:
- 基于迁移的攻击:攻击者先在一个自己拥有的、与目标模型可能相似的本地模型(称为“替代模型”)上,生成对抗样本。由于对抗样本具有一定的可迁移性,这些样本有很大概率也能对黑盒目标模型生效。这种方法查询次数少,但成功率依赖于替代模型与目标模型的相似度。
- 基于查询的攻击:直接对目标模型进行大量查询,通过零阶优化方法(如有限差分法)来迭代生成对抗样本。这种方法不依赖替代模型,更通用,但查询次数多,容易触发API的速率限制和异常报警。
3.2 实操:使用Boundary Attack进行黑盒攻击
我们以图像分类模型为例,使用一种经典的、仅需标签信息的黑盒攻击方法——Boundary Attack。它的思路非常直观:从一个目标类别的随机样本开始,逐步向原始图像靠近,同时保持在模型的决策边界之外(即保持被错误分类)。
环境准备:
# 主要使用 ART 库 pip install adversarial-robustness-toolbox # 以及一个目标模型,这里以 PyTorch 的 ResNet50 为例 pip install torch torchvision攻击脚本核心步骤:
import numpy as np from art.attacks.evasion import BoundaryAttack from art.estimators.classification import PyTorchClassifier import torch import torchvision.models as models from PIL import Image import torchvision.transforms as transforms # 1. 加载并准备目标模型(模拟黑盒环境,我们实际上能调用其预测函数) model = models.resnet50(pretrained=True) model.eval() # 将PyTorch模型包装成ART可识别的分类器 classifier = PyTorchClassifier( model=model, loss=torch.nn.CrossEntropyLoss(), input_shape=(3, 224, 224), nb_classes=1000, clip_values=(0, 1) ) # 2. 加载原始图像并预处理 transform = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), ]) original_image = Image.open("cat.jpg") # 假设这是一张“猫”的图片 x_original = transform(original_image).unsqueeze(0).numpy() # 获取原始预测 pred_original = classifier.predict(x_original) original_label = np.argmax(pred_original, axis=1)[0] print(f"原始预测标签: {original_label}") # 3. 设定攻击目标:我们想让它被误分类为“狗”(假设类别索引为207) target_label = np.array([207]) # 4. 初始化BoundaryAttack attack = BoundaryAttack(estimator=classifier, targeted=False, # 非定向攻击,只要错就行 max_iter=1000, # 最大迭代次数 num_trial=25, # 每次迭代的试探次数 sample_size=20, # 用于估计边界的样本数 init_size=100) # 初始化样本数 # 5. 生成对抗样本 x_adv = attack.generate(x=x_original, y=target_label) # 6. 验证攻击效果 pred_adv = classifier.predict(x_adv) adv_label = np.argmax(pred_adv, axis=1)[0] print(f"对抗样本预测标签: {adv_label}") # 计算扰动大小 perturbation = np.linalg.norm(x_adv - x_original) print(f"扰动范数: {perturbation}") # 可视化保存 adv_image = transforms.ToPILImage()(torch.from_numpy(x_adv.squeeze(0))) adv_image.save("cat_adv.jpg")实操心得与参数调优:
max_iter与成功率/扰动权衡:迭代次数越多,越有可能找到扰动更小的对抗样本,但查询次数也呈线性增长。在实际对抗中,需要在隐蔽性(查询次数)和攻击强度(扰动大小)之间权衡。我们测试发现,对于ResNet50,500-1000次迭代通常能在可接受的扰动下达到80%以上的攻击成功率。init_size的重要性:初始随机样本的数量决定了攻击的起点。如果起点离决策边界太远,攻击可能收敛很慢甚至失败。适当增大init_size可以提高攻击成功率,但会增加初始阶段的查询开销。- 仅标签信息 vs. 置信度信息:Boundary Attack只需要模型输出最终的类别标签,这非常贴近真实的黑盒场景(很多API只返回Top-1标签)。如果API返回各类的置信度分数,攻击者可以利用更多信息(如基于置信度的攻击方法),攻击效率会更高。
- 人眼不可感知性:生成的
cat_adv.jpg看起来和原图几乎一模一样,但模型却坚定地认为它是一条“狗”。这直观地展示了对抗样本的隐蔽性和危险性。
注意:在实际攻击测试中,务必在你自己拥有完全控制权的模型和环境上进行,严禁对任何未授权的第三方服务进行攻击测试,这不仅是法律问题,也违背职业道德。
4. 模型窃取攻击实践:复制你的“大脑”
如果说黑盒攻击是“欺骗”,那么模型窃取就是“克隆”。攻击者通过查询目标模型的API,收集(输入,输出)对,然后用这些数据训练一个自己的模型。这个“山寨模型”的功能可能与原模型高度相似,从而窃取了包含大量数据知识和训练成本的知识产权。
4.1 攻击原理与分类
模型窃取攻击的核心在于,模型的预测行为(即输入到输出的映射函数)本身是有价值的。攻击者不需要知道模型内部的权重,只需要模仿这个映射函数。
根据攻击者能获取的API信息不同,窃取攻击可分为:
- 标签窃取:API只返回硬标签(如“猫”)。攻击者需要收集大量数据,并用这些标签训练一个新模型。这可以看作是一个有监督学习问题,但训练数据是“偷来”的。
- 置信度窃取:API返回各类别的置信度分数(如“猫: 0.85, 狗: 0.10, ...”。这为攻击者提供了更丰富的监督信号,通常能训练出更接近原模型的替代品。
- 逻辑值窃取:API返回Softmax前的逻辑值(Logits)。这几乎等同于白盒信息,窃取出的模型相似度会非常高。
4.2 实操:使用Jacobian-based Dataset Augmentation进行高效窃取
我们实践一种相对高效的模型窃取方法,它不仅收集数据,还会主动生成对区分模型决策边界更有帮助的样本,从而用更少的查询次数,获得性能更好的替代模型。
环境与目标设定:假设我们有一个黑盒图像分类API(我们用一个本地训练的CNN模型victim_model来模拟),攻击者初始只有一个小型公开数据集(如CIFAR-10的子集)。攻击目标是训练一个替代模型substitute_model,使其在未见过测试集上的预测与victim_model尽可能一致。
攻击步骤详解:
- 初始数据收集:用初始种子数据集
S0查询黑盒API,获得标签,形成第一批训练对(x, y_victim)。 - 替代模型训练:用这批数据训练一个替代模型(结构可以与原模型不同)。
- 基于Jacobian的数据增强:
- 这是关键步骤。对于当前替代模型,计算其预测对输入数据的Jacobian矩阵(即梯度)。Jacobian矩阵的方向指示了模型预测最敏感的变化方向。
- 沿着这个方向对现有数据
S_i进行微小扰动,生成新的数据点x_new = x + ε * sign(Jacobian)。 - 将这些新数据点
x_new提交给黑盒API查询,获得新的标签y_victim_new。 - 将新数据对加入训练集:
S_{i+1} = S_i ∪ {(x_new, y_victim_new)}。
- 迭代:用增广后的数据集
S_{i+1}重新训练或微调替代模型,然后重复步骤3。经过多轮迭代,替代模型会逐渐逼近黑盒模型的决策边界。
简化代码示例:
import torch import torch.nn as nn import torch.optim as optim from torch.autograd import grad import numpy as np # 模拟黑盒模型(受害者模型) class VictimModel(nn.Module): # ... 假设这是一个已训练好的复杂CNN pass victim_model = VictimModel().eval() # 模拟黑盒API查询函数 def query_blackbox(input_tensor): with torch.no_grad(): output = victim_model(input_tensor) return output # 这里假设返回logits # 攻击者的替代模型(结构可以更简单) class SubstituteModel(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 16, 3) self.fc = nn.Linear(16*14*14, 10) # CIFAR-10 假设 def forward(self, x): x = torch.relu(self.conv1(x)) x = x.view(x.size(0), -1) x = self.fc(x) return x substitute_model = SubstituteModel() optimizer = optim.Adam(substitute_model.parameters(), lr=0.001) # 初始种子数据 S0 initial_data = torch.randn(100, 3, 32, 32) # 100张随机图 initial_labels = query_blackbox(initial_data).argmax(dim=1) # 训练替代模型初始版本 # ... 训练代码省略 # Jacobian-based 数据增强核心函数 def jacobian_augmentation(substitute_model, current_data, epsilon=0.01): new_data_list = [] new_label_list = [] for x in current_data: x.requires_grad = True output = substitute_model(x.unsqueeze(0)) # 计算输出相对于输入的Jacobian(取第一个输出的梯度) jacobian = grad(outputs=output[:, 0], inputs=x, create_graph=False)[0] # 生成扰动样本 x_new = x + epsilon * jacobian.sign() x_new = torch.clamp(x_new, 0, 1) # 假设输入归一化到[0,1] x_new = x_new.detach() # 查询黑盒API获取新标签 with torch.no_grad(): label_new = query_blackbox(x_new.unsqueeze(0)).argmax() new_data_list.append(x_new) new_label_list.append(label_new) return torch.stack(new_data_list), torch.stack(new_label_list) # 多轮窃取迭代 substitute_train_set = [(initial_data[i], initial_labels[i]) for i in range(100)] for round in range(5): # 进行5轮数据增强 print(f"窃取轮次: {round+1}") # 用当前数据集训练替代模型 # ... 训练代码 # 对当前训练集中的每个样本进行Jacobian增强 current_data = torch.stack([d for d, _ in substitute_train_set]) augmented_data, augmented_labels = jacobian_augmentation(substitute_model, current_data) # 将新数据加入训练集 for i in range(len(augmented_data)): substitute_train_set.append((augmented_data[i], augmented_labels[i])) print(f"训练集大小: {len(substitute_train_set)}")实测效果与洞察:我们在一组简单的图像分类任务上测试,经过3-5轮Jacobian增强,替代模型在与黑盒模型保持相同网络结构的情况下,测试集准确率差距可以从最初的30%缩小到10%以内。如果替代模型结构更接近原模型,这个差距会更小。
关键发现:模型窃取的成功率与查询次数和查询数据的分布强相关。盲目随机查询效率很低,而像Jacobian增强这类主动学习式的方法,能用更少的查询(通常数千到数万次)获得性能不错的替代模型。这对于按查询次数收费的商用AI API来说,攻击成本是可控的,风险极高。
5. 防御策略探讨:从被动响应到主动免疫
在亲身实践了攻击之后,我们更能从攻击者的思维中跳出来,思考如何构建有效的防御体系。防御不是单点技术,而是一个覆盖模型全生命周期的系统工程。
5.1 针对黑盒攻击的防御
输入预处理与净化:
- 随机化:在模型推理前,对输入图像进行随机裁剪、小幅旋转、添加微小噪声等。这可以破坏对抗样本中精心构造的扰动模式。例如,
RandomResizedCrop和ColorJitter是常用的增强手段,可以在线应用。 - 去噪与平滑:使用图像滤波器(如高斯滤波、中值滤波)或基于AI的去噪器(如DnCNN)对输入进行平滑处理。这能有效过滤掉高频的对抗扰动。
- 特征压缩:采用JPEG压缩等有损压缩方法。对抗扰动对压缩非常敏感,而正常图像的主要特征得以保留。这是一种简单高效的防御方法。
- 随机化:在模型推理前,对输入图像进行随机裁剪、小幅旋转、添加微小噪声等。这可以破坏对抗样本中精心构造的扰动模式。例如,
模型鲁棒性增强:
- 对抗训练:这是目前最有效的根本性防御方法之一。在模型训练时,将生成的对抗样本(可以是白盒或黑盒方法生成的)加入训练集,让模型学会正确分类这些“困难样本”。公式可以简化为:
min_θ E_(x,y)~D [max_δ∈Δ L(f_θ(x+δ), y)],即最小化在最坏扰动下的损失。缺点是训练成本极高,且可能轻微降低正常样本的准确率。 - 梯度掩码/随机化:有意让模型的梯度变得不光滑或不可预测,增加基于梯度估计的攻击难度。例如,在模型中插入随机失活(Dropout)层或在推理时使用随机化激活函数。
- 对抗训练:这是目前最有效的根本性防御方法之一。在模型训练时,将生成的对抗样本(可以是白盒或黑盒方法生成的)加入训练集,让模型学会正确分类这些“困难样本”。公式可以简化为:
检测与预警:
- 构建对抗样本检测器:训练一个二分类模型,用于区分正常样本和对抗样本。可以使用对抗样本和正常样本的特征差异(如局部平滑性、噪声统计特性)作为输入。
- 监控API调用模式:黑盒攻击通常需要大量、密集的查询。监控单个IP或用户在一段时间内的查询频率、查询数据的分布(如是否高度相似、是否集中在决策边界附近),可以有效地发现探测行为。设置合理的QPS(每秒查询率)限制和异常报警规则是必须的。
5.2 针对模型窃取的防御
API输出限制与模糊化:
- 仅返回Top-1标签:这是最简单的防御,大大增加了窃取攻击的难度,因为攻击者失去了置信度提供的丰富监督信号。
- 置信度平滑或离散化:不返回精确的浮点数置信度,而是返回离散化的等级(如“高/中/低”)或对置信度加入少量随机噪声。
- 返回不一致结果:对于高度相似的连续查询,可以随机地返回略有不同的结果(在可接受的误差范围内),干扰攻击者构建一致的数据集。
查询监控与速率限制:
- 严格的速率限制:不仅限制每秒请求数,还应限制每日、每用户的总查询量,大幅提高攻击者的时间和经济成本。
- 检测查询序列模式:模型窃取攻击的查询数据往往不是自然分布,而是带有明显的探索性(如Jacobian增强产生的数据)。可以分析查询序列的多样性、熵值,检测是否存在系统性探测行为。
- 水印与指纹:在返回的预测结果中嵌入不易察觉的、特定的模式(数字水印),或者对特定类型的查询返回特殊的“指纹”响应。一旦在外部发现疑似窃取的模型,可以通过检查其对水印样本的响应来追溯和举证。
法律与技术合同保护:
- 完善服务条款:在API使用协议中明确禁止模型逆向工程、窃取及用于训练竞争性模型的行为。
- 输出日志与审计:详细记录所有查询的元数据(IP、时间、输入哈希、输出),为可能的司法取证提供支持。
5.3 构建纵深防御体系
没有任何一种单一防御是万无一失的。最有效的策略是纵深防御,将上述手段组合起来:
- 第一层(入口):严格的API网关,实施身份认证、速率限制和基础输入检查(如尺寸、格式)。
- 第二层(预处理):对输入进行随机化、压缩等净化操作。
- 第三层(模型层):部署经过对抗训练的鲁棒模型,或集成多个模型进行投票。
- 第四层(输出层):对输出进行模糊化处理(如Top-1标签)。
- 第五层(监控与响应):实时监控异常查询模式,配备自动化的对抗样本检测和告警系统,并准备好事件响应流程。
6. 实践总结与未来挑战
通过这次从攻击到防御的实践调研,我最深刻的体会是:AI安全是一个动态的攻防博弈过程,没有一劳永逸的银弹。今天有效的防御方法,明天可能就被新的攻击策略所绕过。例如,近年来出现的自适应攻击,会针对特定的防御机制进行优化,使得许多检测方法失效。
对于企业和开发者而言,当务之急是提升对AI安全威胁的能见度。这需要:
- 安全左移:在模型设计、训练阶段就引入安全考量,比如采用对抗训练、进行鲁棒性评估。
- 持续监控:将模型API像其他关键业务接口一样纳入安全监控体系,关注异常流量和预测结果分布。
- 红蓝对抗:定期对自己的AI系统进行安全审计和渗透测试,模拟真实攻击,主动发现脆弱点。
- 成本权衡:所有的防御都会带来额外的计算开销、延迟或准确率损失。需要在安全性、性能和成本之间找到符合业务需求的平衡点。
一个容易被忽略但至关重要的点是:人的因素。许多安全漏洞源于配置错误、密钥泄露或内部威胁。因此,对运维、开发人员进行AI安全意识培训,与建立技术防御体系同等重要。
最后,分享一个我们在测试中的小技巧:在评估模型鲁棒性时,不要只依赖单一的对抗攻击算法(如FGSM或PGD)来生成测试样本。最好使用一个对抗样本生成工具包(如ART、Foolbox),用其中多种攻击方法(包括黑盒和白盒)进行综合测试。这样得到的鲁棒性评估结果会更全面,更能反映模型在真实对抗环境下的表现。防御的本质,是比攻击者想得更多、更远。