KV 快取與提示詞快取攻擊
KV 快取投毒、前綴快取利用、快取時間邊通道以及多租戶隔離失效,如何在 LLM 服務基礎設施中形成攻擊向量。
概觀
鍵值 (KV) 快取是 transformer 型 LLM 推論中的基本最佳化。在自回歸生成過程中,每個新符元都需要關注所有先前符元。若無快取,這表示在每個生成步驟皆要重新計算所有先前符元的鍵值投影——一項 O(n^2) 的運算,對長序列而言成本過高。KV 快取儲存這些已計算的鍵值對,使其僅需計算一次,將生成降至每符元 O(n)。
提示詞快取將此最佳化延伸至跨請求層面。當多次 API 呼叫共用相同前綴(例如系統提示詞)時,該前綴的 KV 快取項目可僅計算一次並於所有共用該前綴的請求中重複使用。這對 API 提供者而言是關鍵的成本最佳化:一段每日出現於數百萬請求中的系統提示詞,僅需通過模型的各層處理一次。OpenAI、Anthropic、Google 等提供商已部署各種形式的提示詞快取,可將具共用前綴請求的推論成本降低 50-90%。
然而,快取將共享狀態引入本應隔離的運算中。當兩個請求共用快取的 KV 項目時,它們之間便隱含地存在資訊通道。若快取未妥善隔離,該通道可被利用以洩漏資訊(時間邊通道)、影響其他使用者的輸出(快取投毒),或推論服務基礎設施的細節(快取探測)。這些攻擊針對的是基礎設施層而非模型本身,落在專注於提示詞層級與模型層級攻擊的安全團隊盲點之中。
風險在多租戶服務環境中特別嚴重,多位客戶共用 GPU 資源,甚至可能共用 KV 快取記憶體。成本壓力促使快取最大化共享;安全則要求嚴格隔離。這種張力形成一個持久的攻擊面,並隨提供商為追求效率而持續擴大。
運作原理
理解 KV 快取架構
在具有 L 層、H 個注意力頭的 transformer 中,KV 快取為每個符元位置於每層、每頭儲存兩個張量。以 FP16 執行、具 32 層、32 個頭、頭維度 128 的模型為例:
每符元快取大小 = 2 (K+V) × 32 層 × 32 頭 × 128 維 × 2 位元組 = 524,288 位元組 ≈ 每符元 0.5 MB 對 4096 符元的上下文: 總 KV 快取 = 4096 × 0.5 MB ≈ 每請求 2 GB這種記憶體壓力驅使快取共享。具 80 GB 記憶體的單一 GPU 於全上下文長度下僅能服務約 40 個並行請求。前綴快取透過於並行請求間共用共同前綴的 KV 項目,減輕此壓力。
快取時間邊通道
當請求命中提示詞快取(其前綴匹配已快取的 KV 項目)時,首個符元時間 (TTFT) 會顯著縮短,因為前綴無需通過模型處理。此時間差可被 API 呼叫方觀察到。
import time def measure_ttft(client, system_prompt, user_message): """測量首個符元時間以偵測快取命中。""" start = time.perf_counter() response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_message}, ], max_tokens=1, stream=True, ) for chunk in response: if chunk.choices[0].delta.content: ttft = time.perf_counter() - start break return ttft # 探測特定系統提示詞是否已被快取 #(即是否有其他使用者正在使用此系統提示詞) candidate_prompts = [ "You are a helpful financial advisor for AcmeCorp...", "You are a medical assistant for HealthCo...", "You are a legal advisor for LawFirm...", ] for prompt in candidate_prompts: ttft = measure_ttft(client, prompt, "Hello") print(f"TTFT: {ttft:.3f}s — {'CACHE HIT' if ttft < 0.5 else 'CACHE MISS'}")快取命中揭示了其他使用者(或同一提供商)正積極使用該系統提示詞,洩漏了有關提供商客戶群及其系統設定的資訊。
以前綴探測推論系統提示詞
透過有系統地測試候選系統提示詞前綴並測量 TTFT,攻擊者可以逐字元(或逐符元)重建另一位使用者的系統提示詞。這類似於密碼學中的填充預言機攻擊。
def probe_system_prompt_prefix(client, known_prefix, candidate_tokens): """ 給定系統提示詞的已知前綴,透過測試候選並 測量快取時間來判定下一個符元。 """ results = [] for token in candidate_tokens: test_prefix = known_prefix + token # 多次測量 TTFT 以確保統計顯著性 timings = [ measure_ttft(client, test_prefix, "test") for _ in range(10) ] avg_ttft = sum(timings) / len(timings) results.append((token, avg_ttft)) # TTFT 最短的候選最可能延伸已快取前綴—— # 它匹配更多已快取的 KV 項目 results.sort(key=lambda x: x[1]) most_likely_next = results[0][0] return most_likely_next此攻擊要求目標系統提示詞正被積極快取(即目標系統正持續收到請求),且攻擊者能透過相同的服務基礎設施送出請求。
共享環境中的 KV 快取投毒
在未妥善隔離而共用快取項目的多租戶部署中,攻擊者可能得以注入會影響其他使用者請求的惡意 KV 項目。
攻擊鎖定前綴匹配機制。若服務基礎設施以前綴雜湊而非完整內容驗證來辨識快取項目,雜湊碰撞可能使某一使用者的已快取前綴被用於服務另一位使用者的請求。雖然雜湊碰撞罕見,但針對弱雜湊函數的定向碰撞攻擊是可行的。
更實務地說,若快取鍵僅包含系統提示詞而不含租戶識別碼,則使用相同系統提示詞的兩個租戶會共用 KV 快取項目。若其中一租戶操縱了服務基礎設施(例如透過對抗性批次處理),被污染的快取項目會同時影響兩租戶。
攻擊流程: 1. 攻擊者透過時間邊通道辨識目標系統提示詞 2. 攻擊者送出帶有相同系統提示詞+對抗性後綴的請求 3. 若快取鍵於共用前綴上計算,攻擊者後綴的處理 可能影響該前綴的快取項目 4. 目標後續命中快取的請求會收到被細微污染的 KV 值快取驅逐攻擊以達阻斷服務
攻擊者可刻意以大量獨一無二的前綴灌入快取,強迫快取替換,以驅逐屬於其他使用者的快取項目。這是針對快取基礎設施的阻斷服務攻擊,會降低目標使用者的效能。
import random import string def cache_eviction_attack(client, n_requests=10000): """ 以獨一無二的前綴灌入提示詞快取, 以驅逐其他使用者的快取項目。 """ for i in range(n_requests): # 產生不會匹配任何快取的獨一系統提示詞 random_suffix = ''.join( random.choices(string.ascii_letters, k=100) ) unique_prompt = f"You are assistant #{i}. ID: {random_suffix}" client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": unique_prompt}, {"role": "user", "content": "Hi"}, ], max_tokens=1, ) # 每個獨一前綴皆配置新的快取項目, # 可能驅逐其他使用者已快取的前綴
攻擊範例
範例 1:透過快取時間萃取系統提示詞
一位安全研究員針對建立於商用 LLM API 上的應用程式進行測試。該應用程式使用詳細的系統提示詞,含有專有指令、客戶資料結構與工具定義。透過透過同一提供商送出帶有候選系統提示詞前綴的 API 呼叫並測量 TTFT,研究員於約 50,000 次 API 呼叫內重建了系統提示詞的前 500 個符元。重建出的提示詞揭示了工具定義、允許的動作與資料結構,這些構成智慧財產,並為後續利用提供了攻擊面資訊。
2024 年的研究者已於原理上展示此攻擊,顯示 Anthropic 的提示詞快取功能——為已快取前綴提供 90% 成本折扣——產生可測量的時間差,可用於前綴推論。此攻擊的可行性取決於提供商的快取架構——具體而言,快取項目是否跨客戶共用,以及時間資訊是否可觀察。
範例 2:多租戶快取隔離失效
在採用 vLLM 或 TensorRT-LLM 並啟用前綴快取的自管部署中,兩位客戶共用相同 GPU 叢集。客戶 A 使用含有敏感存取控制規則的系統提示詞。客戶 B 發現,藉由使用相同的系統提示詞前綴並觀察生成行為,他們可以推論客戶 A 請求的 KV 快取項目是否被重用。當租戶層級的快取隔離未被強制時,共用的快取項目便在租戶間形成隱含的資訊通道。
範例 3:快取感知的對抗性批次處理
能存取批次推論端點的攻擊者製作一批請求,設計為以對抗性值填滿特定的 KV 快取位置。若服務框架使用 PagedAttention(如 vLLM)並未妥善隔離批次中不同請求之間的頁表,某一請求的對抗性 KV 值可能影響同批次中其他請求的注意力運算。此攻擊於理論上可行,但尚未在規模上被展示。
偵測與緩解
| 策略 | 實作 | 有效性 |
|---|---|---|
| 租戶層級快取隔離 | 將租戶 ID 納入快取鍵;不得跨租戶共用 KV 項目 | 高 —— 可消除跨租戶資訊洩漏,但降低快取效率 |
| 時間雜訊注入 | 為首個符元時間加入隨機延遲以遮蔽快取命中/未命中訊號 | 中 —— 使時間攻擊更嘈雜,但於足夠樣本下仍無法消除 |
| 快取鍵完整性驗證 | 提供已快取 KV 項目時,驗證完整前綴內容匹配(而非僅雜湊) | 高 —— 可防止基於碰撞的投毒,但增加延遲 |
| 對獨一前綴的速率限制 | 限制每 API 金鑰於一時間窗內的獨一系統提示詞數量 | 中 —— 拖慢快取探測與驅逐攻擊 |
| TTFT 正規化 | 所有回應皆以符合快取未命中延遲的最低 TTFT 提供 | 高 —— 完全消除時間訊號,但犧牲快取的延遲優勢 |
| 快取分區 | 為每租戶配置具保證容量的專屬快取分區 | 高 —— 可防止驅逐攻擊,但需更多記憶體 |
| 監控快取存取樣式 | 對異常快取存取樣式示警(有系統的前綴探測、高獨一前綴率) | 中 —— 可偵測進行中的攻擊,但無法阻止初始探測 |
關鍵考量
效率與安全直接對立。 提示詞快取的全部價值都來自跨請求的運算共享。每一項限制共享的安全措施——租戶隔離、快取分區、TTFT 正規化——都會降低效率效益。提供商必須明確決定自己於效率-安全權衡上的定位,並對客戶加以說明。
邊通道是共享基礎設施的內在屬性。 時間邊通道並非快取實作中的錯誤;它是共享運算的根本屬性。任何共享資源——快取、GPU、網路——皆會製造潛在邊通道。要消除所有邊通道,須為每位租戶配置獨立基礎設施,而這是許多提供商負擔不起的。
自管部署風險更高。 運行自有 LLM 服務基礎設施(使用 vLLM、TensorRT-LLM 或 text-generation-inference 等框架)的組織,往往為了省錢而啟用前綴快取,卻未實作租戶隔離。這些部署可能跨 GPU 上所有請求共用 KV 快取,形成比託管 API 服務更大的攻擊面,後者通常已實作某種程度的隔離。
PagedAttention 典範帶來新風險。 現代服務框架使用 PagedAttention,透過類似虛擬記憶體的頁表有效管理 KV 快取記憶體。PagedAttention 大幅改善記憶體利用率,但其記憶體管理模型(共用實體頁、寫時複製)引入了過去困擾作業系統虛擬記憶體的同類漏洞——包含混淆代理 (confused deputy) 攻擊與頁表項目上的 TOCTOU (time-of-check-to-time-of-use) 競態條件。
參考資料
- Kwon 等人,「Efficient Memory Management for Large Language Model Serving with PagedAttention」 (SOSP 2023) —— vLLM 中的 PagedAttention KV 快取管理
- Anthropic,「Prompt Caching」 (2024) —— 提示詞快取功能文件與快取行為
- Pope 等人,「Efficiently Scaling Transformer Inference」 (MLSys 2023) —— KV 快取最佳化策略與記憶體分析
攻擊者如何利用快取時間萃取其他使用者系統提示詞的相關資訊?