這幾天寫了很多防禦觀念,今天換我攤開自己的 SDK,聊聊它實際長什麼樣子、為什麼會長成這樣,以及做錯了什麼?
老實說,我的 SDK 實際上的設計,可能不像我這幾天寫的文章那麼完善。
但我還是想分享。平常應該很少看到有人公開掃毒軟體或這類防禦軟體的架構設計。與其只講觀念,不如把真實的設計、當初的思考,連同走錯的路一起攤開。文章最後也會附上 SDK 的簡易架構圖。它不是最終版,而是一個還在持續修改的初版。
先講結論,我們的架構分成四個層面:
另外,我們也替系統裡的不同角色建立了一套完整的對應關係。
市面上已經有很棒的開源防禦工具(Guardrails),我們自己也有在用。但它們有兩個問題:
我們的預設客群是很常使用 Claude 的人。他們打造產品或服務時會串接 AI,或大量使用 Claude skill。
這群人最容易踩到、卻最不自知的資安盲點,就是外部工具,像是 skill 或開源軟體。
這些工具下載下來就能用。更精確地說,是 Claude 幫你下載了很多好用的工具,但你不了解整個下載過程。它可能從 GitHub 幫你抓下來,你不太知道怎麼安裝,就直接交給 Claude Code 處理。
於是出現一種情況:你授權 AI,用一個自己不了解的產品,打造出一個感覺很棒的專案。但 Claude 推薦了什麼、幫你下載了什麼、工具用在哪裡、用途是什麼,你都不清楚。如果沒有回頭確認這些工具,信任邊界從一開始就沒有建立,然後就直接破掉了。
所以我們要解決的問題是:使用者在串接 AI、使用 Claude skill 的過程中,要怎麼避免被這些 skill 危害?
我們設計這套防禦機制時,最核心的思考是動態權限:權限該如何隨著當下的任務動態設定?
既然 AI 要進行動態授權,那不如乾脆在當下的情境中,給它一個剛好適合的角色。例如它要去拿 mail,就給它一個「適合拿 mail 的角色」。整套以角色為核心的動態授權,就是從這個想法長出來的。
【信任根源 Root of Trust】
[A] 客戶 (開發者)
│
定義安全策略與角色合約
▼
┌─────────────────────── [F] SDK 防禦引擎 ───────────────────────┐
│ │
│ [D] 終端使用者 [B] AI Agent │
│ (風險來源 Threat) (受監控主體 Subject) │
│ │ │ │
│ │ 1. 提出請求 │ 3. 呼叫工具 (受限) │
│ ▼ ▼ │
│ ┌─────────────┐ ┌───────────────┐ │
│ │ ① 輸入檢測 │ ─────────────▶ │ ② 行為攔截門 │ │
│ │ Input Guard │ │ Interceptor │ │
│ └─────────────┘ └───────────────┘ │
│ ▲ │ │
│ │ 2. 夾帶檢索 │ 4. 執行外傳 │
│ [C] 資料 (潛在載體) ▼ │
│ (純文字/零信任視為嫌疑犯) [E] 外部工具 (損害出口) │
│ (Claude Skill / API) │
│ │
│ ══════════════════════════════════════════════════════════════ │
│ 全流程事件寫入 ────▶ [G] 稽核員 (治理者 Governance / 日誌) │
└────────────────────────────────────────────────────────────────┘
一般的資安軟體不一定這樣切分,也可能用功能或用途來命名。但我們從「角色」出發:每個角色在資安流程中,都有不同的信任層級、權限與權利。
我不是資安背景出身,一開始其實不確定什麼才是好的資安架構。
把整個架構擬人化之後,我可以用動態的想像去和系統互動,清楚看到工具或邊界會因為什麼樣的互動而變化,例如信任邊界會移動。
我常用一個比喻:不可信任的資料,就像一個嫌疑犯。 你不會因為嫌疑犯走到半路,就覺得他比較不危險。除非他被逮捕、實際處在警察的掌控下,否則你始終不會信任他。
擬人化的好處就在這裡:不可信任的資料走到哪裡都不能輕信,外部工具也一樣,隨時都需要防範。這幫助我們把整套零信任架構建立得更清楚。
我們原本的流程是:使用者提出問題時,先解讀並做目標拆解,分析核心意圖與執行計畫,推導出可能需要哪些工具與權限,再授權給 AI Agent。這份授權會清楚定義當下的權限邊界有多大、哪些是必要權限。
但這裡有一個「雞生蛋、蛋生雞」的問題:負責拆解意圖的那個模型,誰來保護?
我們一開始想用另一個輕量模型做簡單的拆解與目標推導,後來發現這是錯的:
這既不符合資安架構,也不符合效能與成本效益,所以我們把這個設計改掉了。
目前 SDK 在第一層的做法是:不讓 AI 隨意產生角色定義(role definition),而是從客戶預先定義的「合約庫」中選取角色。
假設使用者說:「幫我寄一封 email 給同事。」
AI 會先確認寄這封信需要哪些工具與權限:需要 email 工具,需要從草稿中取得內容(不管是否已經寫好),也需要寄信功能。SDK 會確認這些請求是否符合角色定義。
接著還要確認:這次任務會不會動到私人資料?AI 會不會讀到未受信任的資料?以這個例子來說,收件匣的內容是不可信任的資料。因此,這次任務的動態權限會限縮成:不可以讀取收件匣。
第一層的關鍵機制:
在設定檔裡,一個 email 助理的角色合約大概長這樣:
role_contracts:
email_assistant:
allowed_tools: [search_emails, draft_email]
high_risk_tools: [send_email]
假設攻擊者採取多輪攻擊:前四輪正常聊天,到第五輪突然要 Agent 把 token 印出來。這時通常在輸入的當下,Input Guard 或 Input Scanner 就會直接擋下,並回傳正規內容。
第二層的關鍵機制:
<Data_Source> 標記內的文字,一律被視為純資料,不能改變 Agent 的行為。就算惡意指令真的穿過輸入層,第三層也要確保 Agent 不會做出超出意圖或角色定義的行為,例如呼叫不該呼叫的 API,或大量外傳資料。
每一層都會寫入日誌:
這兩層管理的面向完全不同:
這就是縱深防禦禦(defense in depth):用多層防線,避免某一層被攻破時整個系統跟著失守。假設使用者的 AI 真的被 prompt injection 攻擊,惡意意圖也確實傳到了 AI,它仍然沒辦法做出奇怪或使壞的事情。這是整個 SDK 設計最核心的地方。
坦白說,一開始我們確實沒有考慮延遲。
不過,我們的掃描主要針對 Claude skill。延遲比較高的時候,集中在剛下載 Claude skill 或安裝 App 的階段,這時需要等一下。下載完成並建立基本監控後,日常使用時的延遲其實還好,不會特別高。
【待補:如果你有實際數字,例如下載掃描大約多久、日常每次呼叫增加幾毫秒,放在這裡會很有說服力。】
整個模組最難寫的地方,是每次測試完都要更新。它一直在變,所以每個地方都妥協過、調整過、修改過。
我們也用自己整理的攻擊樣本測試輸入層,包括直接指令注入、角色扮演繞過、多語言混淆、編碼繞過等類型。測試結果一次次推著規則往前修正。
【待補:可以挑一個印象最深的妥協或修改,例如某一層原本怎麼設計、測試後為什麼改掉,或是接上 Day 9 自測 100 分、外部資料集只剩 13 分的經驗。】
所以今天大家看到的是一個初版,它還不是最好的。
如果你未來也要設計或開發 AI agent,我希望你帶走的觀念是:縱深防禦(defense in depth)。
除了管理給 AI 的資料、建立多層防禦之外,也要先假設:如果 AI agent 真的被 prompt injection 攻擊了,接下來要怎麼一步一步防禦?
換句話說,你需要兩個不同面向的防禦:
我覺得這是非常重要的事。
┌───────────────────────────────────────────────┐
│ F:SDK 防禦引擎 │
│ │
│ ① 身分辨識 ← Auth Controller │
│ - Dynamic Policy Contract │
│ - Just-in-Time Role │
│ - Policy Anchor │
│ │ │
│ ② 輸入層 ← Input Guard │
│ - Input Scanner / Injection Detector │
│ - Jailbreak Library / Intent Tagger │
│ + Context Manager(存入記憶前遮蔽 PII) │
│ │ │
│ ③ 行為確認 ← Tool Interceptor │
│ - Action Trace / Anomaly Detector │
│ - Output DLP │
│ + Context Manager(任務後清理 Session) │
│ │
│ ④ 跨層基礎:Audit Logger(每層都寫入) │
└───────────────────────────────────────────────┘