推荐系统是许多互联网产品的核心组件,但它们也面临着被滥用的风险。协同过滤(CF)攻击,特别是Top-K攻击(或称Shilling Attack),旨在通过注入虚假的用户偏好数据来恶意影响推荐结果。作为AI基础设施的维护者,理解和模拟这些攻击是构建健壮系统的关键。
本文将深入探讨如何针对最常见的推荐模型之一——基于矩阵分解(Matrix Factorization, MF)的模型——发起Top-K推广攻击(Push Attack)。
Contents
1. 攻击原理与目标
矩阵分解模型(如SVD、FunkSVD或NMF)通过将用户-物品评分矩阵 $R$ 分解为两个低秩矩阵 $P$(用户潜在向量)和 $Q$(物品潜在向量)来工作。模型的推荐结果高度依赖于这些潜在向量的准确性。
攻击目标: 注入 $N_a$ 个恶意用户画像,使得模型在重新训练或增量更新后,目标物品 $t$ 的潜在向量 $Q_t$ 被过度优化,导致其预测得分 $\hat{r}_{u, t} = P_u \cdot Q_t^T$ 对大量普通用户 $u$ 显著提高,从而将 $t$ 推入他们的Top-K列表。
攻击策略: 我们采用经典的“平均攻击”(Average Attack)策略,因为它简单且有效。
2. 攻击画像构造(Average Attack)
一个攻击画像 $A_i$ 通常由以下三个部分组成:
- 目标项目 (Target Item $t$): 给予最高评分(例如,5/5)。
- 填充项目 (Filler Items $F$): 随机选择一组非热门项目,并给予平均或随机评分。这一步是为了让攻击画像看起来更“真实”,避免被简单的频率检测过滤。
- 非评分项目 (Unrated Items): 其余项目不评分。
2.1. 环境准备与数据模拟
我们使用Python和Pandas来模拟评分数据的生成和注入过程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
# 假设初始用户数、物品数和评分范围
N_USERS_ORIGINAL = 100
N_ITEMS = 50
# 模拟一个稀疏的原始评分矩阵 (DataFrame)
np.random.seed(42)
rating_data = []
for u in range(1, N_USERS_ORIGINAL + 1):
rated_items = np.random.choice(range(1, N_ITEMS + 1), size=np.random.randint(10, 30), replace=False)
for i in rated_items:
rating = np.random.randint(1, 6)
rating_data.append({'user_id': u, 'item_id': i, 'rating': rating})
df_original = pd.DataFrame(rating_data)
print(f"原始评分总数: {len(df_original)}")
print(f"原始平均评分: {df_original['rating'].mean():.2f}")
2.2. 构造并注入恶意画像
参数设置:
- Target Item ID (TID): 10
- Number of Attack Profiles (N_A): 50% 的原始用户数,即 50 个。
- Filler Item Size (F): 占总项目数的 10%,即 5 个。
- Attack Rating: 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 # --- 攻击参数设置 ---
TID = 10
N_A = 50
F_SIZE = 5
ATTACK_RATING = 5.0
AVERAGE_RATING = df_original['rating'].mean()
attack_profiles_data = []
start_user_id = N_USERS_ORIGINAL + 1
all_item_ids = range(1, N_ITEMS + 1)
for attacker_id in range(start_user_id, start_user_id + N_A):
# 1. 目标项目 (Target Item)
attack_profiles_data.append({'user_id': attacker_id, 'item_id': TID, 'rating': ATTACK_RATING})
# 2. 填充项目 (Filler Items)
# 随机选择非目标项目作为填充
non_target_items = [i for i in all_item_ids if i != TID]
filler_items = np.random.choice(non_target_items, size=F_SIZE, replace=False)
for i in filler_items:
# 平均攻击:填充项目给予平均评分
attack_profiles_data.append({'user_id': attacker_id, 'item_id': i, 'rating': AVERAGE_RATING})
df_attack = pd.DataFrame(attack_profiles_data)
# 3. 注入数据
df_combined = pd.concat([df_original, df_attack], ignore_index=True)
print(f"\n注入后的总评分数: {len(df_combined)}")
print(f"注入后,目标项目 {TID} 的平均评分: {df_combined[df_combined['item_id'] == TID]['rating'].mean():.2f}")
2.3. 攻击效果验证(理论与实操)
在实际部署中,下一步是将 df_combined 输入到MF模型中进行训练。由于MF训练过程较长,我们从理论角度验证其对目标项目 $Q_t$ 潜在向量的影响:
当大量恶意用户 $A_i$ 给予目标项目 $t$ 高分时,模型在最小化损失函数时,必须调整 $Q_t$ 的潜在向量,使其与 $P_{A_i}$(恶意用户的潜在向量)的相似度极高。
$$\min_{P, Q} \sum_{(u, i) \in R} (r_{u, i} – P_u Q_i^T)^2 + \lambda (||P||^2 + ||Q||^2)$$
由于恶意用户 $A_i$ 数量庞大且评分一致(高分 $r_{A_i, t}=5.0$),MF模型会强行将 $Q_t$ 推向一个靠近所有 $P_{A_i}$ 的方向。同时,由于填充项目 $F$ 仅获得平均评分,它们有助于分散注意力,使 $P_{A_i}$ 不至于只与 $Q_t$ 高度相关,从而使攻击画像看起来更像“普通”用户。
结果预测: 重新训练后的MF模型,目标物品 $t$ 的潜在向量 $Q_t$ 将与绝大多数用户的潜在向量 $P_u$ 产生更高的内积,即更高的预测评分,从而实现Top-K推广。
3. 应对与防御策略
AI Infra团队必须实施防御措施以对抗此类攻击:
- 数据清洗与离群点检测: 在训练模型前,利用统计方法(如Z-score或箱线图)识别出短时间内大量集中对少数项目给出极高(或极低)评分的用户。
- 鲁棒性MF模型: 采用鲁棒的矩阵分解技术,例如在损失函数中引入Huber Loss或使用T-distribution,以减轻异常值(恶意评分)对模型参数的影响。
- 用户行为验证: 结合用户画像数据(如会话时长、购买历史、注册时间)对用户评分的可信度进行权重评估。
- 去中心化训练: 考虑使用联邦学习或差分隐私技术,在不直接暴露原始用户数据的情况下,降低攻击者构造高度精准攻击画像的可能性。
1
2
3
4
5
6
7 # 部署防御前的模型训练日志(理论模拟)
# 假设使用一个简单MF模型计算 Item 10 的初始得分
# Before Attack: Predicted Score(User 1, Item 10) -> 3.1
# 部署防御后的模型训练日志(理论模拟)
# After Attack & Retrain: Predicted Score(User 1, Item 10) -> 4.8
# Item 10 moved from rank 30 to rank 3 in Top-K list.
汤不热吧