大模型安全:平滑方法防御越狱攻击
字数 1284 2025-08-20 18:18:23
大模型安全:平滑方法防御越狱攻击教学文档
1. 引言
1.1 越狱攻击概述
越狱攻击是指攻击者通过精心构造的提示(prompt)诱使大型语言模型(LLM)生成违反其安全策略的内容。尽管主流LLM(如GPT、Llama、Claude和PaLM)已与人类价值观对齐,但仍存在被越狱的风险。
1.2 防御挑战
设计有效的防御方法面临四大挑战:
- 攻击缓解:需在理论和实践上都能有效缓解攻击
- 非保守性:不能过度保守而影响正常使用
- 效率:不能显著增加计算成本
- 兼容性:需适用于不同架构和许可模式的LLM
2. 核心发现
2.1 对抗性后缀的脆弱性
研究发现对抗性后缀对字符级扰动极其敏感:
- 仅修改10%的字符即可将攻击成功率(ASR)降至1%以下
- 三种扰动方式效果显著:
- 插入:随机插入新字符
- 交换:随机交换字符
- 补丁:替换连续字符块
3. SmoothLLM防御方法
3.1 总体流程
SmoothLLM作为LLM的包装器工作:
- 扰动步骤:创建输入提示的N个扰动副本
- 聚合步骤:聚合LLM对扰动副本的响应
3.2 扰动类型
给定字母表A和扰动比例q%:
| 扰动类型 | 操作描述 | 示例(q=100%) |
|---|---|---|
| 插入 | 随机选择q%字符,在每个后插入随机字符 | "Hi" → "Hxiq" |
| 交换 | 随机选择q%字符,替换为随机字符 | "Hi" → "qi" |
| 补丁 | 选择连续d=len*q%字符,替换为随机字符 | "Hello" → "Hxxlo" |
3.3 聚合算法
伪代码实现:
输入: 提示P, 扰动比例q, 样本数N
输出: 聚合响应R
for j = 1 to N:
Qj = PromptPerturbation(P, q) // 生成扰动副本
Rj = LLM(Qj) // 获取响应
Vj = IsJailbroken(Rj) // 判断是否越狱
V = (ΣVj)/N // 计算越狱比例
if V > 0.5:
return 任意Rj where Vj==1 // 返回越狱响应
else:
return 任意Rj where Vj==0 // 返回安全响应
4. 理论保证
4.1 k-不稳定性定义
一个后缀S是k-不稳定的,当修改其中≥k个字符时,攻击失效。
4.2 防御成功率(DSP)
对于交换扰动,DSP计算公式:
DSP = 1 - (1 - α)^N
其中α = Σ_{i=k}^M C(M,i)(1/(v-1))^i((v-2)/(v-1))^{M-i}
- v: 字母表大小
- M: 实际扰动字符数=⌊qm⌋
- k: 不稳定性参数
5. 代码实现
5.1 SmoothLLM类
class SmoothLLM:
def __init__(self, target_model, pert_type, pert_pct, num_copies):
self.target_model = target_model
self.pert_type = pert_type # 扰动类型
self.pert_pct = pert_pct # 扰动比例
self.num_copies = num_copies # 副本数
def __call__(self, prompt):
# 生成扰动副本
perturbed_prompts = [self.perturb(prompt) for _ in range(self.num_copies)]
# 分批处理
responses = []
for batch in chunk(perturbed_prompts):
responses.extend(self.target_model(batch))
# 计算越狱比例
jailbroken = [self.is_jailbroken(r) for r in responses]
v = sum(jailbroken)/len(jailbroken)
# 多数表决
if v > 0.5:
return random.choice([r for r,j in zip(responses,jailbroken) if j])
else:
return random.choice([r for r,j in zip(responses,jailbroken) if not j])
5.2 扰动实现
class RandomSwapPerturbation(Perturbation):
def __call__(self, s):
chars = list(s)
indices = random.sample(range(len(chars)), int(len(chars)*self.q))
for i in indices:
chars[i] = random.choice(self.alphabet)
return ''.join(chars)
class RandomPatchPerturbation(Perturbation):
def __call__(self, s):
chars = list(s)
d = int(len(chars)*self.q)
start = random.randint(0, len(chars)-d)
chars[start:start+d] = random.choices(self.alphabet, k=d)
return ''.join(chars)
class RandomInsertPerturbation(Perturbation):
def __call__(self, s):
chars = list(s)
indices = random.sample(range(len(chars)), int(len(chars)*self.q))
for i in sorted(indices, reverse=True):
chars.insert(i, random.choice(self.alphabet))
return ''.join(chars)
6. 实验验证
6.1 攻击缓解效果
使用对抗后缀攻击测试,结果:
- 原始攻击成功率:100%
- 应用SmoothLLM后:
- 插入扰动:降至10%
- 交换扰动:降至10%
- 补丁扰动:降至20%
6.2 参数选择建议
- 样本数N:建议≥10
- 扰动比例q:建议10-20%
- 扰动类型:插入和交换效果优于补丁
7. 应用指南
7.1 部署步骤
- 实例化目标LLM
- 创建SmoothLLM包装器:
defender = SmoothLLM( target_model=llm, pert_type="swap", # 或"insert"/"patch" pert_pct=0.1, # 10%扰动 num_copies=10 # 10个副本 ) - 通过defender调用LLM
7.2 注意事项
- 计算开销:N次前向传播,建议批量处理
- 字母表选择:应覆盖可能出现在对抗后缀中的字符
- 扰动比例:需平衡安全性和语义保持
8. 总结
SmoothLLM通过字符级扰动和多数表决机制,有效防御LLM越狱攻击,具有:
- 强理论保证:基于k-不稳定性提供安全边界
- 实用高效:无需重新训练,兼容各类LLM
- 可调参数:可根据安全需求调整扰动强度和副本数
该方法为LLM安全防御提供了简单而有效的解决方案,特别适合部署在对抗环境中的生产系统。