3、对抗性攻击原理:对抗性样本的定义、对抗性攻击的分类(白盒/黑盒)、对抗性攻击的常见算法(FGSM, PGD)
好,咱们进入正题。这一章讲的是对抗性攻击的原理,说白了就是研究「怎么骗过AI模型」。我在做红蓝对抗的时候,发现很多安全工程师对这块的理解停留在「加噪声」的层面,其实远没那么简单。
先问大家一个问题:你给模型一张熊猫的照片,模型说是熊猫。但你在上面加了一层人眼几乎看不出来的微小扰动,模型就说是长臂猿了。这合理吗?不合理,但这就是对抗性攻击。
对抗性样本的定义
对抗性样本,简单来说就是「精心构造的输入」。它跟普通样本的区别在于:
- 对人有欺骗性:人眼看不出明显差异
- 对模型有欺骗性:模型会给出完全错误的输出
我举个例子。假设你有一个图像分类模型,用来识别路标。攻击者在一张「停止」标志上贴了几个小贴纸,人眼看起来还是「停止」,但模型却识别成了「限速80」。这在自动驾驶场景下是要出人命的。
核心定义:对抗性样本 = 原始样本 + 精心设计的微小扰动
数学上可以表示为:x' = x + δ,其中δ是扰动,且||δ||很小,但f(x') ≠ f(x)
嗯,这里要注意:扰动不是随便加的。我见过一些新手直接往图片上撒椒盐噪声,那叫「数据损坏」,不叫「对抗性攻击」。对抗性攻击的扰动是经过优化的,目标就是让模型犯错。
对抗性攻击的分类
对抗性攻击主要分两类:白盒攻击和黑盒攻击。这两者的区别,说白了就是「你对模型了解多少」。
白盒攻击
白盒攻击,就是攻击者知道模型的一切信息:
- 模型的结构(几层卷积、几个全连接)
- 模型的参数(权重、偏置)
- 模型的训练数据(如果有的话)
这种情况下,攻击者可以精确计算梯度,找到让模型犯错的最优扰动。我在项目中遇到过,一个白盒攻击场景下,FGSM只需要一步就能让ResNet-50的准确率从95%掉到20%以下。效率极高,但前提是你得拿到模型。
个人经验:白盒攻击在红队演练中非常有用。如果你能拿到目标模型的权重文件,白盒攻击是最快验证模型脆弱性的方式。我曾经在一次渗透测试中,直接从云存储桶里找到了未加密的模型文件,然后用了不到10分钟就生成了对抗性样本。
黑盒攻击
黑盒攻击就难多了。攻击者只知道模型的输入和输出,不知道内部结构。这就像你面对一个黑箱子,只能通过「按按钮看反应」来摸索规律。
黑盒攻击的常见思路有两种:
- 查询攻击:不断向模型发送请求,根据返回结果推测决策边界
- 迁移攻击:用自己的替代模型生成对抗性样本,然后拿去攻击目标模型
你想想看,黑盒攻击虽然效率低,但更贴近真实场景。现实中的攻击者哪有那么容易拿到你的模型权重?
| 对比维度 | 白盒攻击 | 黑盒攻击 |
|---|---|---|
| 所需信息 | 模型全部信息 | 仅输入输出 |
| 攻击成功率 | 高(通常>90%) | 低(通常30-60%) |
| 所需查询次数 | 1次(直接计算) | 数百到数千次 |
| 实战场景 | 内部测试、模型泄露 | API攻击、黑盒渗透 |
对抗性攻击的常见算法
讲完分类,咱们来看具体的算法。我挑两个最经典的讲:FGSM和PGD。这两个算法是基础,理解了它们,其他变种基本就是换汤不换药。
FGSM(快速梯度符号法)
FGSM是2014年Goodfellow等人提出的,可以说是对抗性攻击的「开山之作」。它的思路非常直接:
既然模型是根据梯度来学习的,那我们就沿着梯度的反方向走一步,让模型犯错。
公式很简单:x' = x + ε · sign(∇x J(θ, x, y))
其中:
- ε是扰动强度(通常0.01-0.1)
- sign()是取符号函数
- ∇x J是损失函数对输入的梯度
# FGSM的PyTorch实现示例
def fgsm_attack(model, images, labels, epsilon=0.1):
# 开启梯度计算
images.requires_grad = True
# 前向传播
outputs = model(images)
loss = F.nll_loss(outputs, labels)
# 反向传播,计算梯度
model.zero_grad()
loss.backward()
# 获取梯度符号
sign_data_grad = images.grad.data.sign()
# 生成对抗性样本
perturbed_images = images + epsilon * sign_data_grad
# 裁剪到有效范围
perturbed_images = torch.clamp(perturbed_images, 0, 1)
return perturbed_images
我个人习惯用ε=0.1做初始测试。太小了没效果,太大了人眼能看出来。我曾经在图像分类任务上试过,ε=0.1时攻击成功率能到80%以上,而且人眼几乎看不出区别。
避坑指南:FGSM有个致命弱点——它只走一步。如果这一步没走对,攻击就失败了。我曾经在某个高分辨率图像数据集上测试,FGSM的攻击成功率只有40%左右。后来换成PGD,成功率直接飙到95%。
PGD(投影梯度下降)
PGD是FGSM的升级版。它不满足于走一步,而是走多步,每一步都检查一下有没有走偏。
PGD的核心思想:
- 从原始样本附近随机选一个起点
- 沿着梯度方向走一小步(类似FGSM)
- 把结果投影回允许的扰动范围内
- 重复步骤2-3,直到达到预设的迭代次数
# PGD的PyTorch实现示例
def pgd_attack(model, images, labels, epsilon=0.1, alpha=0.01, num_iter=40):
# 保存原始图像
original_images = images.clone().detach()
# 随机初始化扰动
delta = torch.rand_like(images) * 2 * epsilon - epsilon
delta = torch.clamp(delta, -epsilon, epsilon)
for i in range(num_iter):
# 计算当前对抗性样本
perturbed_images = original_images + delta
perturbed_images.requires_grad = True
# 前向传播
outputs = model(perturbed_images)
loss = F.nll_loss(outputs, labels)
# 反向传播
model.zero_grad()
loss.backward()
# 更新扰动
grad = perturbed_images.grad.data
delta = delta + alpha * grad.sign()
# 投影到epsilon球内
delta = torch.clamp(delta, -epsilon, epsilon)
delta = torch.clamp(original_images + delta, 0, 1) - original_images
return original_images + delta
你想想看,PGD为什么比FGSM强?因为它有「纠错机制」。FGSM走一步就完事了,万一走歪了也没办法。PGD每走一步都检查一下,确保扰动在合法范围内,而且不断往最优方向调整。
我记得有一次做模型鲁棒性评估,甲方要求用最严格的攻击测试。我直接上了PGD,迭代40步,ε设0.1。结果他们的模型准确率从95%直接掉到3%。甲方工程师脸都绿了,问我是不是用了什么黑科技。我说没有,就是PGD,你们模型太脆弱了。
实战建议:
- 快速验证用FGSM,几秒钟出结果
- 严格评估用PGD,迭代20-40步比较合理
- 如果PGD都攻不破,说明模型有一定鲁棒性
- ε值从0.01开始试,逐步增大到0.3
最后说一句,对抗性攻击不是目的,目的是让我们知道模型有多脆弱。下一章我会讲怎么防御这些攻击,到时候你会发现,攻防其实是一体两面。