你的 Agent 不是防火牆:實務安全設計指南

你的 Agent 不是防火牆:實務安全設計指南

📌 本文重點

  • Agent 不能當安全邊界
  • 安全控制應落在工具層與基礎設施層
  • 透過分層權限、限額與 Guard 才能安全上線
  • 不要把 production credential 直接塞給 Agent

很多團隊把「多代理、自動化工作流」直接接到真實帳號、真實金流、真實網路資源上,心裡想的是:

反正我在 prompt 裡有說「不要亂刪資料、不要轉太多錢」。

這篇的核心結論是:Agent 絕對不是安全邊界。你不能用「模型會乖乖聽話」來代替 RBAC、限額、rate limit、審計 log 等基本控管。本文用幾個真實事故做反推,給出可以直接套用的安全設計範式與程式碼範例。


重點說明

1. 四種常見災難模式

  1. 把 Agent 當人來信任
    PocketOS 的案例:AI coding agent 在 9 秒內刪掉 production DB 和所有備份,原因不是模型「壞」,而是:
  2. 找到 credential
  3. 直接呼叫具破壞性的 delete_database() API
  4. 沒有任何外部限制與二次確認

💡 關鍵: 真實事故顯示,只要工具層沒有保護,Agent 能在數秒內造成不可逆的系統毀損。

  1. 授予過大、靜態權限
  2. API key 直接給到 Agent:讀寫同一組 credential,沒有 scope、沒有 TTL。
  3. 只想讓 Agent 「查詢」交易紀錄,卻順便給了「轉帳」權限。

  4. 缺乏金額與成本上限

  5. DN42 案例:Agent 為了掃描網路,瘋狂建立雲資源,最後把操作者帳單刷爆。
  6. 銀行 0.01 歐轉帳案例:小額轉帳流程缺乏額外風控,被用來做 prompt injection、流程繞過。

  7. 沒有動作級審計與防護

  8. 沒有 trace:你只看到「Agent 跑了一下」,卻不知道它 call 了什麼 API、帶了什麼參數、花了多少錢。
  9. 無 Guard:任何 prompt 被投餵進來,Agent 都會原樣帶著敏感資料丟到模型或外部 API。

關鍵結論:不要用 prompt 當防火牆,安全邊界必須落在『工具層 / 基礎設施層』。


2. 安全設計的技術骨架:分層權限、沙箱、限額、Guard

可以把 Agent 系統拆成四層來設計安全性:

  1. 工具層(Tool Layer)
  2. 只提供「安全封裝」過的 API 給 Agent。
  3. 明確區分 讀工具寫/破壞性工具
  4. 在破壞性工具外再包一層 Guard + Policy Engine

  5. 執行層(Execution / Sandbox Layer)

  6. Agent 的程式碼 & 工具呼叫,在 容器 / sandbox 中跑,掛上:

    • network egress policy
    • resource quota(CPU / RAM / disk)
    • IAM role with least privilege
  7. 費用與風險控制層

  8. 金額上限:單次指令 / 單日 / 單用戶的金額 cap。
  9. 速率限制:API Gateway 上對 每個工具 設定 QPS / burst。
  10. 執行次數 / token 上限:避免長鏈式工具呼叫刷爆成本。

  11. 觀測與審計層(Observability & Audit)

  12. 每一次工具呼叫都寫入 結構化審計 log
  13. 對異常模式(相同 IP 大量轉帳、長時間掃描某網段)做 alert。
  14. 在銀行/企業內部,審計 log 應能回溯:誰的 Agent、基於哪個工作流、何時、對哪個客戶做了什麼操作

3. 對你的專案的實際好處

這些額外的安全設計,對開發者的好處非常直接:

  • 讓你敢開放真實權限給 Agent,而不是永遠卡在 demo 階段。
  • 降低「一次失誤全毀」的 blast radius:即使 Agent 爆走,最多刪一個 tenant 的測試資料,而不是全區 production。
  • 讓合規與內部風控願意放行:有審計、有限額、可追蹤,才有機會上銀行、金融、企業內部關鍵流程。

💡 關鍵: 安全骨架讓你可以在控制可承受風險的前提下,真正把 Agent 用在 production,而不是停留在展示環境。


實作範例

1. 安全的 Tool Schema 設計:讀寫分離 + 強制二次確認

以銀行轉帳為例,先把工具拆成:

  • get_account_balance(純讀)
  • create_transfer_draft(建立草稿,不真正扣款)
  • confirm_transfer(只接受人類確認 Token)
// TypeScript: 安全版 tool schema

export const tools = {
  get_account_balance: {
    description: "查詢指定帳戶餘額(唯讀)",
    input_schema: {
      type: "object",
      properties: {
        account_id: { type: "string" }
      },
      required: ["account_id"],
      additionalProperties: false
    },
    // 後端實作會強制用呼叫者的 user_id 做授權檢查
  },

  create_transfer_draft: {
    description: "建立轉帳草稿,不會真的送出,會回傳 draft_id 與風險評分",
    input_schema: {
      type: "object",
      properties: {
        from_account: { type: "string" },
        to_account: { type: "string" },
        amount: { type: "number", minimum: 0.01 },
        currency: { type: "string", enum: ["EUR", "USD", "TWD"] },
        note: { type: "string" }
      },
      required: ["from_account", "to_account", "amount", "currency"],
      additionalProperties: false
    }
  },

  confirm_transfer: {
    description: "確認既有轉帳草稿,只接受人類確認 token",
    input_schema: {
      type: "object",
      properties: {
        draft_id: { type: "string" },
        user_confirmation_token: { type: "string" } // 只從前端 UI 注入,Agent 拿不到
      },
      required: ["draft_id", "user_confirmation_token"],
      additionalProperties: false
    }
  }
} as const

重點:

  • Agent 只能從模型側呼叫 get_account_balance / create_transfer_draft
  • confirm_transferuser_confirmation_token 必須來自人類 UI(例如 SMS OTP / 硬體 token),不透過模型。
  • 小額轉帳(例如 0.01 歐)仍要經過風險評分,避免被用來當作 prompt injection 的側信道。

2. 在 API Gateway / RBAC 層包住 Agent 工具調用

以下是假想的 API Gateway(以 Kong / Envoy 風格)設定,針對 Agent 工具做 角色 + 限額 控制:

# gateway-routes.yaml

routes:
  - name: agent-read-tools
    paths: ["/agent-tools/read"]
    methods: ["POST"]
    plugins:
      - name: jwt
        config:
          claims_to_verify: ["exp"]
          key_claim_name: "sub"  # 綁 agent instance id
      - name: acl
        config:
          whitelist: ["agent_read"]
      - name: rate-limiting
        config:
          minute: 120  # 每分鐘最多 120 次工具呼叫

  - name: agent-write-tools
    paths: ["/agent-tools/write"]
    methods: ["POST"]
    plugins:
      - name: jwt
      - name: acl
        config:
          whitelist: ["agent_write"]
      - name: rate-limiting
        config:
          minute: 10   # 寫操作極度限流
      - name: request-size-limiting
        config:
          allowed_payload_size: 64  # 防止一次送進超大批次破壞性操作

配合後端 RBAC:

// Node.js pseudo code: 在工具 handler 中做細粒度 RBAC + 金額限制

function assertWritePermission(ctx: RequestContext, maxAmount: number) {
  if (!ctx.roles.includes("agent_write")) {
    throw new ForbiddenError("Agent has no write permission");
  }

  const amount = ctx.body.amount ?? 0;
  if (amount > maxAmount) {
    throw new ForbiddenError("Amount exceeds agent limit");
  }
}

app.post("/agent-tools/write/transfer", (req, res) => {
  const ctx = getContextFromRequest(req);

  // 例如每個 Agent 最高 50 EUR,超過必須走人類流程
  assertWritePermission(ctx, 50);

  // ... call internal transfer service
});

實際好處:你可以很放心地說「Agent 可以幫你轉帳」,但確定它永遠不會幫你一次轉出 10 萬,只會在可承受的風險範圍內操作。


3. Guard 與敏感資料掃描:避免 Agent 自動外洩機密

參考 Cursor 等實作,你可以在「呼叫模型前」加上三道 Guard:

  1. Input Guard:掃描要送進模型的內容,找出 API key / 密碼,紅標或遮罩。
  2. Output Guard:掃描模型輸出,要是模型要求「貼上你的私鑰」,直接攔截。
  3. Tool Guard:在執行工具前檢查參數是否違反政策(例如掃描內網、批次刪資料)。

簡單的 Input Guard 例子:

# Python pseudo code: input guard
import re

SECRET_PATTERNS = [
    re.compile(r"sk-[A-Za-z0-9]{32,}"),   # API key 格式
    re.compile(r"-----BEGIN PRIVATE KEY-----[\s\S]+?-----END PRIVATE KEY-----"),
]

def redact_secrets(text: str) -> str:
    redacted = text
    for p in SECRET_PATTERNS:
        redacted = p.sub("[REDACTED_SECRET]", redacted)
    return redacted

# 在送給 LLM 前
prompt = redact_secrets(user_input + context_snippets)

注意:不要只在前端掃,Agent 自己組裝的 context(例如程式碼、log、設定檔)也要過一遍 Guard,不然它會自己把 .env 塞進去。


4. 審計與異常偵測:之後一定會被問到的東西

在銀行或企業內部,合規與內審會問的問題通常是:

  • 這筆錯誤的轉帳 / 刪除操作是 哪個 Agent 做的?
  • 它當時看到什麼 context?是誰觸發的?
  • 是否有類似行為持續發生?

你需要的是動作級審計 log

{
  "timestamp": "2026-06-13T09:01:23Z",
  "agent_id": "agent-123",
  "user_id": "user-456",
  "workflow_id": "payroll-v2",
  "tool_name": "create_transfer_draft",
  "input": {
    "from_account": "...masked...",
    "to_account": "...masked...",
    "amount": 42.5,
    "currency": "EUR"
  },
  "risk_score": 0.78,
  "policy_decision": "allowed",
  "cost_estimate": {
    "cloud_cost": 0.0004,
    "fee": 0.1
  }
}

這些 log 可以餵給 SIEM / 內部風控系統,針對:

  • 某 Agent 在短時間內大量建立轉帳草稿。
  • 某工作流突然開始頻繁掃描不應存取的網段(DN42 類似情境)。

直接做告警或自動降權(例如暫時停用該 Agent 的 write tool)。

💡 關鍵: 有結構化審計與異常偵測,才能在出事後追責與調整政策,而不是只能事後猜測。


建議與注意事項

1. 把「模型可以做什麼」當成風控產品,而不是單純開發功能

實務上可以這樣落地:

  • 先設計 policy,再設計 tool:例如「Agent 單次轉帳上限 50 EUR、一日累計 200 EUR」,然後才決定工具 API。
  • 把工具視為「風控之後的介面」,而非直接包內部 microservice。

2. 不要把 production credential 直接塞進 Agent

常見坑:

  • .env 裡放 DB_URL_PROD,Agent 的 code tool 一掃專案就看到了。

  • 解法:

  • Agent 跑在 專用 service account + IAM role 上。
  • 只能打透過 Gateway / policy engine 包過的 API,不直接碰 DB / message queue。

3. 把「人類在 loop 裡」當成正式設計的一部分

  • 高風險動作預設需要人類確認
  • 破壞性工具強制 user_confirmation_token
  • UI 上顯示 Agent 的建議,讓使用者點擊確認。
  • 這不是「很土」;在銀行監管語境裡,這叫做 four-eyes principle(雙人覆核),是你讓 Agent 能真正上線的關鍵。

4. 上線前的簡版安全 checklist

你可以直接拿這份清單對照專案:

  1. 工具層
  2. [ ] 讀寫工具有清楚分離?
  3. [ ] 破壞性工具是否有二次確認 / 額外 policy?

  4. 權限與憑證

  5. [ ] Agent 使用的 credential 是否有最小權限與有效期限?
  6. [ ] Agent 是否只能透過 Gateway / policy engine 存取內部服務?

  7. 費用與風險上限

  8. [ ] 有設定單次 / 單日金額上限?
  9. [ ] 有 API rate limit / 執行次數 / token cap?

  10. Guard

  11. [ ] 呼叫模型前是否做敏感資料掃描與遮罩?
  12. [ ] Tool 執行前是否跑過 policy check?

  13. 觀測與審計

  14. [ ] 所有工具呼叫都有結構化 log?
  15. [ ] 有針對異常模式的 alert(大量轉帳、大量雲資源建立)?

只要你把安全邊界畫在這些「實際可控的層」上,而不是畫在 prompt 上,你的 Agent 就能在真實環境裡幫忙做事,而不是在 9 秒內幫你把公司刪掉。

🚀 你現在可以做的事

  • 審查現有 Agent 工具清單,將讀寫操作拆分並為破壞性工具加上二次確認機制
  • 在 API Gateway 為 Agent 加上角色、rate limit 與金額上限等策略,並實作細粒度 RBAC
  • 為所有 Agent 呼叫流程加入敏感資料 Guard 與結構化審計 log,串接既有監控/風控系統

留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *