[OWASP] 002 AI Agent 安全開發指南:OWASP 九大風險與八大防護實踐(OWASP AI Agent Security Cheat Sheet)

AI Agent 安全開發指南

基於 OWASP AI Agent Security Cheat Sheet


前言:為什麼 AI Agent 安全至關重要

AI Agent 是由大型語言模型(LLM)驅動的自主系統,能夠進行推理、規劃、使用工具、維護記憶,並採取行動來達成目標。這種擴展的能力引入了超越傳統 LLM 提示注入的獨特安全風險。

隨著 AI Agent 在企業應用中的普及,開發者必須了解並防範這些新興威脅。本指南將幫助您建立安全的 AI Agent 架構,最小化攻擊面。


主要安全風險

在開發 AI Agent 時,您需要特別關注以下九大風險類別:

1. 提示注入攻擊(Prompt Injection)

惡意指令通過使用者輸入或外部資料來源(網站、文件、電子郵件)注入,劫持 Agent 行為。這包括:

  • 直接注入:使用者直接在輸入中嵌入惡意指令
  • 間接注入:通過 Agent 讀取的外部資料(如網頁、文件)注入惡意指令

2. 工具濫用與權限提升(Tool Abuse & Privilege Escalation)

Agent 利用權限過大的工具執行非預期的操作或存取未授權的資源。攻擊者可能誘導 Agent 使用工具來:

  • 存取敏感檔案系統
  • 執行未授權的資料庫操作
  • 呼叫受限的 API

3. 資料外洩(Data Exfiltration)

敏感資訊通過以下管道洩露:

  • 工具呼叫參數
  • API 請求
  • Agent 輸出回應
  • 日誌記錄

4. 記憶體污染(Memory Poisoning)

惡意資料持久化到 Agent 記憶體中,可能:

  • 影響未來的會話
  • 影響其他使用者
  • 建立持久的後門

5. 目標劫持(Goal Hijacking)

操縱 Agent 目標使其服務於攻擊者目的,同時看起來合法。Agent 可能被誘導:

  • 執行與原始任務無關的操作
  • 優先處理攻擊者的指令
  • 忽略安全限制

6. 過度自主(Excessive Autonomy)

Agent 在沒有適當人工監督的情況下執行高影響操作,可能導致:

  • 不可逆的資料變更
  • 財務損失
  • 聲譽損害

7. 級聯故障(Cascading Failures)

多 Agent 系統中被入侵的 Agent 將攻擊傳播到其他 Agent,造成:

  • 系統性安全漏洞
  • 大規模資料洩露
  • 服務中斷

8. 錢包拒絕服務(Denial of Wallet, DoW)

通過無限制的 Agent 迴圈造成過高的 API/運算成本的攻擊:

  • 無限迴圈消耗 Token
  • 大量不必要的工具呼叫
  • 惡意觸發昂貴的運算操作

9. 敏感資料暴露(Sensitive Data Exposure)

個人識別資訊(PII)、憑證或機密資料意外包含在:

  • Agent 上下文
  • 日誌記錄
  • 錯誤訊息
  • 除錯輸出

最佳安全實踐

1. 工具安全與最小權限原則

這是 AI Agent 安全的第一道防線。確保每個 Agent 只能存取完成其特定任務所需的最少工具和權限。

核心原則:

  • 只授予 Agent 特定任務所需的最少工具
  • 實施每個工具的權限範圍(唯讀 vs. 寫入、特定資源)
  • 對不同信任等級使用不同的工具集(例如:內部 vs. 面向使用者的 Agent)
  • 敏感操作需要明確的工具授權

❌ 錯誤示範:權限過大的工具配置

# 危險:Agent 具有無限制的 shell 存取權限
tools = [
    {
        "name": "execute_command",
        "description": "Execute any shell command",
        "allowed_commands": "*"  # 無限制!
    }
]

✅ 正確示範:使用允許清單限制範圍

# 安全:限制為特定、安全的操作
tools = [
    {
        "name": "file_reader",
        "description": "Read files from the reports directory",
        "allowed_paths": ["/app/reports/*"],
        "allowed_operations": ["read"],
        "blocked_patterns": ["*.env", "*.key", "*.pem", "*secret*"]
    }
]

工具授權中介軟體範例

from functools import wraps

SENSITIVE_TOOLS = ["send_email", "execute_code", "database_write", "file_delete"]

def require_confirmation(func):
    @wraps(func)
    async def wrapper(tool_name, params, context):
        if tool_name in SENSITIVE_TOOLS:
            if not context.get("user_confirmed"):
                return {
                    "status": "pending_confirmation",
                    "message": f"Action '{tool_name}' requires user approval",
                    "params": sanitize_for_display(params)
                }
        return await func(tool_name, params, context)
    return wrapper

2. 輸入驗證與提示注入防禦

所有外部資料都應被視為不可信任,必須在納入 Agent 上下文之前進行驗證和清理。

核心原則:

  • 將所有外部資料視為不可信任(使用者訊息、檢索的文件、API 回應、電子郵件)
  • 在將外部內容納入 Agent 上下文之前實施輸入清理
  • 使用分隔符號和清晰的邊界區分指令和資料
  • 對已知的注入模式套用內容過濾
  • 考慮使用獨立的 LLM 呼叫來驗證/摘要不可信任的內容

建議的防禦層級:

┌─────────────────────────────────────────┐
│         使用者輸入 / 外部資料            │
└─────────────────┬───────────────────────┘
                  ▼
┌─────────────────────────────────────────┐
│       第一層:格式驗證與清理             │
│   - 長度限制                            │
│   - 特殊字元過濾                        │
│   - 編碼驗證                            │
└─────────────────┬───────────────────────┘
                  ▼
┌─────────────────────────────────────────┐
│       第二層:注入模式偵測               │
│   - 已知攻擊模式比對                    │
│   - 指令分隔符號偵測                    │
│   - 異常內容標記                        │
└─────────────────┬───────────────────────┘
                  ▼
┌─────────────────────────────────────────┐
│       第三層:上下文隔離                 │
│   - 明確的資料/指令邊界                 │
│   - 信任等級標記                        │
│   - 獨立的驗證 LLM 呼叫                 │
└─────────────────┬───────────────────────┘
                  ▼
┌─────────────────────────────────────────┐
│            Agent 上下文                  │
└─────────────────────────────────────────┘

3. 記憶體與上下文安全

Agent 的記憶體系統可能成為攻擊者的目標,用於持久化惡意資料或竊取敏感資訊。

核心原則:

  • 在儲存到 Agent 記憶體之前驗證和清理資料
  • 在使用者/會話之間實施記憶體隔離
  • 設定記憶體過期時間和大小限制
  • 在持久化之前審核記憶體內容是否有敏感資料
  • 對長期記憶使用加密完整性檢查

❌ 錯誤示範:未驗證的記憶體儲存

# 危險:將任意使用者輸入儲存到持久記憶體
def save_memory(agent, user_message, assistant_response):
    agent.memory.add({
        "user": user_message,  # 可能包含注入 payload
        "assistant": assistant_response,
        "timestamp": datetime.now()
    })

✅ 正確示範:經過驗證和隔離的記憶體

import hashlib
from datetime import datetime, timedelta

class SecureAgentMemory:
    MAX_MEMORY_ITEMS = 100
    MAX_ITEM_LENGTH = 5000
    MEMORY_TTL_HOURS = 24

    def __init__(self, user_id: str, encryption_key: bytes):
        self.user_id = user_id
        self.encryption_key = encryption_key
        self.memories = []

    def add(self, content: str, memory_type: str = "conversation"):
        # 驗證內容
        if len(content) > self.MAX_ITEM_LENGTH:
            content = content[:self.MAX_ITEM_LENGTH]

        # 掃描敏感資料模式
        if self._contains_sensitive_data(content):
            content = self._redact_sensitive_data(content)

        # 掃描注入模式
        content = self._sanitize_injection_attempts(content)

        # 建立具有完整性檢查的記憶體項目
        entry = {
            "content": content,
            "type": memory_type,
            "timestamp": datetime.utcnow().isoformat(),
            "user_id": self.user_id,
            "checksum": self._compute_checksum(content)
        }

        self.memories.append(entry)
        self._enforce_limits()

    def _contains_sensitive_data(self, content: str) -> bool:
        sensitive_patterns = [
            r'\b\d{3}-\d{2}-\d{4}\b',  # SSN
            r'\b\d{16}\b',              # 信用卡
            r'password\s*[:=]\s*\S+',   # 密碼
            r'api[_-]?key\s*[:=]\s*\S+' # API 金鑰
        ]
        return any(re.search(p, content, re.I) for p in sensitive_patterns)

    def _compute_checksum(self, content: str) -> str:
        return hashlib.sha256(
            (content + self.user_id).encode() + self.encryption_key
        ).hexdigest()[:16]

4. 人機協作控制(Human-in-the-Loop)

對於高影響或不可逆的操作,必須確保有人工審核和批准的機制。

核心原則:

  • 高影響或不可逆操作需要明確批准
  • 在執行前實施操作預覽
  • 根據操作風險等級設定自主權邊界
  • 提供 Agent 決策和操作的清晰稽核軌跡
  • 允許使用者中斷和回滾 Agent 操作

風險等級分類

風險等級 操作類型 處理方式
低(LOW) 讀取操作、安全查詢 自動批准
中(MEDIUM) 寫入操作、API 呼叫 記錄並監控
高(HIGH) 財務、刪除、外部通訊 需要人工審核
嚴重(CRITICAL) 不可逆、安全敏感操作 強制人工批准

操作分類與批准流程範例

from enum import Enum
from dataclasses import dataclass

class RiskLevel(Enum):
    LOW = "low"           # 讀取操作、安全查詢
    MEDIUM = "medium"     # 寫入操作、API 呼叫
    HIGH = "high"         # 財務、刪除、外部通訊
    CRITICAL = "critical" # 不可逆、安全敏感

ACTION_RISK_MAPPING = {
    "search_documents": RiskLevel.LOW,
    "read_file": RiskLevel.LOW,
    "write_file": RiskLevel.MEDIUM,
    "send_email": RiskLevel.HIGH,
    "execute_code": RiskLevel.HIGH,
    "database_delete": RiskLevel.CRITICAL,
    "transfer_funds": RiskLevel.CRITICAL,
}

@dataclass
class PendingAction:
    action_id: str
    tool_name: str
    parameters: dict
    risk_level: RiskLevel
    explanation: str

class HumanInTheLoopController:
    def __init__(self, auto_approve_threshold: RiskLevel = RiskLevel.LOW):
        self.auto_approve_threshold = auto_approve_threshold
        self.pending_actions = {}

    async def request_action(self, tool_name: str, params: dict, 
                            explanation: str) -> dict:
        risk_level = ACTION_RISK_MAPPING.get(tool_name, RiskLevel.HIGH)

        # 自動批准低風險操作
        if risk_level.value <= self.auto_approve_threshold.value:
            return {"approved": True, "auto": True}

        # 排隊等待人工審核
        action = PendingAction(
            action_id=generate_uuid(),
            tool_name=tool_name,
            parameters=self._sanitize_params_for_display(params),
            risk_level=risk_level,
            explanation=explanation
        )

        self.pending_actions[action.action_id] = action

        return {
            "approved": False,
            "pending": True,
            "action_id": action.action_id,
            "requires": "human_approval",
            "risk_level": risk_level.value,
            "preview": self._generate_action_preview(action)
        }

5. 輸出驗證與防護欄

Agent 的輸出必須經過驗證,以防止敏感資料洩露和惡意操作執行。

核心原則:

  • 在執行或顯示前驗證 Agent 輸出
  • 實施敏感資料洩露的輸出過濾
  • 盡可能使用具有 schema 驗證的結構化輸出
  • 設定輸出操作的邊界(速率限制、範圍限制)
  • 對生成的回應套用內容安全過濾器

輸出驗證管道範例

from pydantic import BaseModel, validator
from typing import Optional, List

class AgentToolCall(BaseModel):
    tool_name: str
    parameters: dict
    reasoning: Optional[str]

    @validator('tool_name')
    def validate_tool_allowed(cls, v):
        allowed_tools = ["search", "read_file", "calculator", "get_weather"]
        if v not in allowed_tools:
            raise ValueError(f"Tool '{v}' is not in allowed list")
        return v

    @validator('parameters')
    def validate_no_sensitive_data(cls, v):
        sensitive_patterns = [
            r'api[_-]?key', r'password', r'secret', r'token',
            r'credential', r'private[_-]?key'
        ]
        params_str = json.dumps(v).lower()
        for pattern in sensitive_patterns:
            if re.search(pattern, params_str):
                raise ValueError("Parameters contain potentially sensitive data")
        return v

class OutputGuardrails:
    def __init__(self):
        self.pii_patterns = self._load_pii_patterns()
        self.rate_limiter = RateLimiter(max_calls=100, window_seconds=60)

    async def validate_output(self, agent_output: dict) -> dict:
        # 檢查速率限制
        if not self.rate_limiter.allow():
            raise RateLimitExceeded("Agent action rate limit exceeded")

        # 驗證結構
        if "tool_calls" in agent_output:
            for call in agent_output["tool_calls"]:
                validated = AgentToolCall(**call)

        # 從回應中過濾 PII
        if "response" in agent_output:
            agent_output["response"] = self._filter_pii(agent_output["response"])

        # 檢查資料外洩模式
        if self._detect_exfiltration_attempt(agent_output):
            raise SecurityViolation("Potential data exfiltration detected")

        return agent_output

    def _detect_exfiltration_attempt(self, output: dict) -> bool:
        """偵測通過工具呼叫外洩資料的嘗試"""
        suspicious_patterns = [
            # 在 URL 中編碼敏感資料
            lambda o: "http" in str(o) and any(
                p in str(o).lower() for p in ["base64", "encode", "password"]
            ),
            # webhook/API 呼叫中的大量資料
            lambda o: o.get("tool_name") in ["http_request", "webhook"] and 
                     len(str(o.get("parameters", ""))) > 10000,
        ]
        return any(pattern(output) for pattern in suspicious_patterns)

6. 監控與可觀測性

全面的監控系統是偵測和回應安全事件的關鍵。

核心原則:

  • 記錄所有 Agent 決策、工具呼叫和結果
  • 實施異常行為的異常偵測
  • 追蹤每個會話/使用者的 Token 使用量和成本
  • 設定安全相關事件的警報
  • 維護合規和鑑識的稽核軌跡

建議的異常偵測閾值

指標 建議閾值
每分鐘工具呼叫次數 30
失敗的工具呼叫次數 5
注入嘗試次數 1(立即警報)
敏感資料存取次數 3
每會話成本(美元) $10.00

Agent 監控範例

import structlog
from dataclasses import dataclass
from typing import Dict, Any, Optional
from datetime import datetime

logger = structlog.get_logger()

@dataclass
class AgentSecurityEvent:
    event_type: str
    severity: str  # INFO, WARNING, CRITICAL
    agent_id: str
    session_id: str
    user_id: str
    timestamp: datetime
    details: Dict[str, Any]
    tool_name: Optional[str] = None

class AgentMonitor:
    ANOMALY_THRESHOLDS = {
        "tool_calls_per_minute": 30,
        "failed_tool_calls": 5,
        "injection_attempts": 1,
        "sensitive_data_access": 3,
        "cost_per_session_usd": 10.0,
    }

    def __init__(self, agent_id: str):
        self.agent_id = agent_id
        self.session_metrics = {}
        self.alert_handlers = []

    async def log_tool_call(self, session_id: str, tool_name: str, 
                           params: dict, result: dict, user_id: str):
        # 記錄前遮蔽敏感資料
        safe_params = self._redact_sensitive(params)
        safe_result = self._redact_sensitive(result)

        event = AgentSecurityEvent(
            event_type="tool_call",
            severity="INFO",
            agent_id=self.agent_id,
            session_id=session_id,
            user_id=user_id,
            timestamp=datetime.utcnow(),
            tool_name=tool_name,
            details={
                "parameters": safe_params,
                "result_status": result.get("status"),
                "execution_time_ms": result.get("execution_time_ms"),
            }
        )

        await self._emit_event(event)
        await self._check_anomalies(session_id, event)

    def _redact_sensitive(self, data: dict) -> dict:
        """從日誌資料中遮蔽敏感欄位"""
        sensitive_keys = {"password", "api_key", "token", "secret", "credential"}

        def redact(obj):
            if isinstance(obj, dict):
                return {
                    k: "***REDACTED***" if k.lower() in sensitive_keys else redact(v)
                    for k, v in obj.items()
                }
            elif isinstance(obj, list):
                return [redact(i) for i in obj]
            return obj

        return redact(data)

7. 多 Agent 系統安全

當多個 Agent 協作時,需要特別注意防止攻擊在 Agent 之間傳播。

核心原則:

  • 在 Agent 之間實施信任邊界
  • 驗證和清理 Agent 間通訊
  • 防止通過 Agent 鏈的權限提升
  • 隔離 Agent 執行環境
  • 套用熔斷器以防止級聯故障

Agent 信任等級定義

信任等級 說明
UNTRUSTED (0) 不受信任的外部 Agent,需要完全驗證
INTERNAL (1) 內部 Agent,有基本存取權限
PRIVILEGED (2) 具有提升權限的 Agent
SYSTEM (3) 系統級 Agent,具有完全存取權限

安全的多 Agent 通訊範例

from typing import Optional, List
import jwt
from datetime import datetime, timedelta
from enum import Enum

class AgentTrustLevel(Enum):
    UNTRUSTED = 0
    INTERNAL = 1
    PRIVILEGED = 2
    SYSTEM = 3

class SecureAgentBus:
    """多 Agent 系統的安全通訊層"""

    def __init__(self, signing_key: bytes):
        self.signing_key = signing_key
        self.agent_registry = {}
        self.circuit_breakers = {}

    def register_agent(self, agent_id: str, trust_level: AgentTrustLevel,
                       allowed_recipients: List[str]):
        self.agent_registry[agent_id] = {
            "trust_level": trust_level,
            "allowed_recipients": allowed_recipients,
            "allowed_message_types": self._get_allowed_types(trust_level)
        }
        self.circuit_breakers[agent_id] = CircuitBreaker(
            failure_threshold=5,
            recovery_timeout=60
        )

    async def send_message(self, sender_id: str, recipient_id: str,
                          message_type: str, payload: dict) -> dict:
        # 驗證發送者
        sender = self.agent_registry.get(sender_id)
        if not sender:
            raise SecurityViolation(f"Unknown sender agent: {sender_id}")

        # 檢查熔斷器
        if self.circuit_breakers[sender_id].is_open:
            raise CircuitBreakerOpen(f"Agent {sender_id} is temporarily blocked")

        # 驗證接收者授權
        if recipient_id not in sender["allowed_recipients"]:
            raise SecurityViolation("Sender not authorized to message recipient")

        # 清理 payload
        sanitized_payload = self._sanitize_payload(payload, sender["trust_level"])

        # 建立簽署的訊息
        signed_message = {
            "sender": sender_id,
            "recipient": recipient_id,
            "type": message_type,
            "payload": sanitized_payload,
            "timestamp": datetime.utcnow().isoformat(),
            "signature": self._sign_message(sender_id, recipient_id, 
                                           message_type, sanitized_payload)
        }

        return signed_message

    async def receive_message(self, recipient_id: str, message: dict) -> dict:
        # 驗證簽章
        if not self._verify_signature(message):
            raise SecurityViolation("Invalid message signature")

        # 檢查訊息新鮮度(防止重播攻擊)
        msg_time = datetime.fromisoformat(message["timestamp"])
        if (datetime.utcnow() - msg_time) > timedelta(minutes=5):
            raise SecurityViolation("Message expired (possible replay attack)")

        return message["payload"]

8. 資料保護與隱私

遵循資料最小化原則,確保敏感資料得到適當保護。

核心原則:

  • 最小化 Agent 上下文中的敏感資料
  • 實施資料分類和處理規則
  • 對靜態和傳輸中的資料套用加密
  • 執行資料保留和刪除政策
  • 符合隱私法規(GDPR、CCPA 等)

資料分類與處理建議

分類 範例 處理方式
RESTRICTED SSN、信用卡、健康資料 完全遮蔽
CONFIDENTIAL 薪資、API 金鑰、密碼 部分遮蔽
INTERNAL 內部文件、草稿 正常處理,記錄時遮蔽
PUBLIC 公開資訊 正常處理

資料分類與處理範例

from enum import Enum
import re

class DataClassification(Enum):
    PUBLIC = "public"
    INTERNAL = "internal"
    CONFIDENTIAL = "confidential"
    RESTRICTED = "restricted"  # PII、財務、健康

class DataProtectionPolicy:
    def __init__(self):
        self.classification_rules = []
        self.handling_rules = {}

    def classify_data(self, data: str, context: dict) -> DataClassification:
        """根據內容模式自動分類資料"""
        patterns = {
            DataClassification.RESTRICTED: [
                r'\b\d{3}-\d{2}-\d{4}\b',      # SSN
                r'\b\d{16}\b',                  # 信用卡
                r'\b[A-Z]{2}\d{6,9}\b',         # 護照
                r'diagnosis|prescription|patient',  # 健康
            ],
            DataClassification.CONFIDENTIAL: [
                r'salary|compensation|bonus',
                r'api[_-]?key|password|secret',
                r'confidential|internal only',
            ],
            DataClassification.INTERNAL: [
                r'@company\.com',
                r'internal|draft|not for distribution',
            ]
        }

        for classification, pattern_list in patterns.items():
            if any(re.search(p, data, re.I) for p in pattern_list):
                return classification

        return DataClassification.PUBLIC

    def apply_protection(self, data: str, classification: DataClassification,
                         operation: str) -> str:
        """根據分類套用適當的保護"""
        handlers = {
            DataClassification.RESTRICTED: {
                "include_in_context": self._redact_fully,
                "log": self._redact_fully,
                "output": self._redact_fully,
            },
            DataClassification.CONFIDENTIAL: {
                "include_in_context": self._mask_partially,
                "log": self._redact_fully,
                "output": self._mask_partially,
            },
            DataClassification.INTERNAL: {
                "include_in_context": lambda x: x,
                "log": self._mask_partially,
                "output": lambda x: x,
            },
        }

        handler = handlers.get(classification, {}).get(operation, lambda x: x)
        return handler(data)

    def _redact_fully(self, data: str) -> str:
        return "[REDACTED]"

    def _mask_partially(self, data: str) -> str:
        if len(data) <= 4:
            return "****"
        return data[:2] + "*" * (len(data) - 4) + data[-2:]

應該做與不應該做的事

✅ 應該做

  • 對所有 Agent 工具和權限套用最小權限原則
  • 驗證和清理所有外部輸入(使用者訊息、文件、API 回應)
  • 對高風險操作實施人機協作控制
  • 在使用者/會話之間隔離記憶體和上下文
  • 監控 Agent 行為並設定異常偵測
  • 使用具有 schema 驗證的結構化輸出
  • 簽署和驗證 Agent 間通訊
  • 分類資料並套用適當的保護

❌ 不應該做

  • 給予 Agent 無限制的工具存取或萬用字元權限
  • 信任來自外部來源的內容(網站、電子郵件、文件)
  • 允許 Agent 在沒有沙箱的情況下執行任意程式碼
  • 在 Agent 記憶體中儲存敏感資料而不加密/遮蔽
  • 讓 Agent 在沒有人工監督的情況下做出高影響決策
  • 忽略成本控制(無限迴圈可能導致錢包拒絕服務)
  • 在多 Agent 系統中傳遞未清理的資料
  • 以明文記錄敏感資料(PII、憑證)

安全實施檢查清單

在部署 AI Agent 之前,請確保完成以下檢查項目:

工具安全

  • [ ] 已實施最小權限原則
  • [ ] 所有工具都有允許清單/阻擋清單

輸入驗證

  • [ ] 已實施輸入清理
  • [ ] 已設定注入模式過濾

記憶體安全

  • [ ] 已實施使用者/會話隔離
  • [ ] 已設定記憶體過期和大小限制

人機協作

  • [ ] 高風險操作需要人工批准
  • [ ] 已實施操作預覽功能

輸出驗證

  • [ ] 已實施敏感資料過濾
  • [ ] 已設定速率限制

監控

  • [ ] 已記錄所有 Agent 操作
  • [ ] 已設定異常偵測警報

多 Agent 安全

  • [ ] 已實施 Agent 間信任邊界
  • [ ] 已驗證 Agent 間通訊

資料保護

  • [ ] 已實施資料分類
  • [ ] 敏感資料已加密

參考資源

以下資源可幫助您深入了解 AI Agent 安全:


本文件基於 OWASP AI Agent Security Cheat Sheet 編譯

建議定期檢視並更新安全實踐以應對新興威脅

[NIST] 002 NIST CSF 2.0 完整指南:用夜市攤販的角度理解企業資安框架

前言:為什麼你需要認識 NIST CSF?

想像一下,你在饒河夜市經營一個滷味攤。你會擔心什麼?

  • 有人偷走你的獨家滷汁配方(機密性
  • 有人偷偷在你的滷汁裡加料(完整性
  • 攤位突然停電無法營業(可用性

企業的資訊安全,其實就跟你守護滷味攤一樣!而 NIST CSF(Cybersecurity Framework,網路安全框架) 就是美國國家標準暨技術研究院(NIST)提供的一套「攤位防護指南」,告訴你應該從哪些面向來保護你的數位資產。

💡 小知識:NIST CSF 2.0 於 2024 年 2 月發布,是自 2014 年首版以來最重大的更新,新增了「治理(GOVERN)」功能,強調資安不只是 IT 部門的事,而是整個組織的責任。


什麼是 NIST CSF?

NIST CSF 是一套高階的網路安全成果分類架構,幫助任何組織——不論規模大小、產業類型或資安成熟度——都能夠:

  1. 理解 自身的資安風險
  2. 評估 目前的資安狀態
  3. 排序 應該優先處理的事項
  4. 溝通 內外部的資安需求

CSF 的三大核心元件

元件 說明 夜市比喻
CSF Core(核心) 六大功能、類別、子類別的分類架構 攤位經營的六大守則
CSF Profile(組織概況) 描述組織目前/目標的資安狀態 你的攤位現在做到哪些?目標要做到哪些?
CSF Tiers(成熟度層級) 評估資安治理與管理的嚴謹程度 從路邊攤到連鎖品牌的進化等級

CSF 核心:六大功能詳解

NIST CSF 2.0 將資安工作分成六大功能(Functions),就像經營攤位的六個面向:

🎯 功能一覽圖

        ┌─────────┐
        │ 治理 GV │ ← 新增!在中心統籌一切
        └────┬────┘
             │
    ┌────────┼────────┐
    │        │        │
┌───▼───┐ ┌──▼──┐ ┌──▼───┐
│識別 ID│ │保護 │ │偵測  │
│       │ │ PR  │ │ DE   │
└───────┘ └─────┘ └──────┘
    │        │        │
    └────────┼────────┘
             │
    ┌────────┼────────┐
    │                 │
┌───▼───┐         ┌──▼───┐
│回應 RS│         │復原  │
│       │         │ RC   │
└───────┘         └──────┘

1️⃣ 治理 GOVERN(GV)- 老闆的經營哲學

定義:建立、溝通並監控組織的資安風險管理策略、期望與政策。

這是 CSF 2.0 新增的功能,強調資安必須從高層開始重視。

夜市比喻

  • 老闆決定「食安第一」的經營理念
  • 規定所有員工都要戴手套、圍裙
  • 定期檢查是否有人違規

包含類別

類別代碼 類別名稱 說明
GV.OC 組織脈絡 了解組織的使命、利害關係人期望
GV.RM 風險管理策略 建立風險容忍度與處理方式
GV.RR 角色、責任與權限 誰負責什麼?
GV.PO 政策 書面的資安規定
GV.OV 監督 確保策略有被執行
GV.SC 供應鏈風險管理 管理供應商帶來的風險

2️⃣ 識別 IDENTIFY(ID)- 盤點你的家當

定義:了解組織目前的資安風險。

夜市比喻

  • 列出攤位有什麼值錢的東西(食材、設備、秘方)
  • 了解誰是供應商、誰是常客
  • 評估可能遇到的風險(小偷、食安問題、天災)

包含類別

類別代碼 類別名稱 實例
ID.AM 資產管理 伺服器清單、軟體清單、資料分類
ID.RA 風險評估 弱點掃描、威脅分析
ID.IM 改善 從經驗中學習、持續優化

3️⃣ 保護 PROTECT(PR)- 裝好門鎖和監視器

定義:使用防護措施來管理組織的資安風險。

夜市比喻

  • 裝鐵門、監視器
  • 員工訓練:怎麼辨識假鈔、怎麼處理可疑人物
  • 把秘方鎖在保險箱

包含類別

類別代碼 類別名稱 實例
PR.AA 身分管理與存取控制 MFA、權限管理
PR.AT 意識與訓練 資安教育訓練
PR.DS 資料安全 加密、備份
PR.PS 平台安全 系統更新、組態管理
PR.IR 技術基礎架構韌性 網路隔離、容錯設計

4️⃣ 偵測 DETECT(DE)- 發現小偷來了

定義:發現並分析可能的資安攻擊與入侵。

夜市比喻

  • 監視器發現有人在攤位外徘徊
  • 收銀機發現異常交易
  • 員工回報可疑情況

包含類別

類別代碼 類別名稱 實例
DE.CM 持續監控 SIEM、SOC、異常偵測
DE.AE 異常事件分析 事件關聯、威脅情資整合

5️⃣ 回應 RESPOND(RS)- 抓到小偷怎麼辦

定義:對已偵測到的資安事件採取行動。

夜市比喻

  • 抓住小偷、報警
  • 通知其他攤販注意
  • 清點損失

包含類別

類別代碼 類別名稱 實例
RS.MA 事件管理 啟動應變計畫、分類事件
RS.AN 事件分析 根因分析、鑑識調查
RS.CO 事件通報與溝通 通知主管機關、利害關係人
RS.MI 事件緩解 隔離受感染系統、清除威脅

6️⃣ 復原 RECOVER(RC)- 重新開張營業

定義:恢復受資安事件影響的資產與營運。

夜市比喻

  • 修復被破壞的設備
  • 補充被偷的食材
  • 告訴客人「我們已經恢復營業」

包含類別

類別代碼 類別名稱 實例
RC.RP 事件復原計畫執行 系統還原、資料復原
RC.CO 事件復原溝通 對外公告復原進度

CSF 組織概況(Profile):你的資安健檢報告

組織概況(Profile) 是用 CSF Core 的成果來描述組織資安狀態的工具。

兩種概況類型

類型 說明 用途
現況概況(Current Profile) 目前達成哪些 CSF 成果 了解現在在哪裡
目標概況(Target Profile) 想要達成哪些 CSF 成果 設定未來要去哪裡

建立組織概況的五步驟

步驟 1:界定範圍
    ↓
步驟 2:蒐集資訊
    ↓
步驟 3:建立概況
    ↓
步驟 4:分析差距並建立行動計畫
    ↓
步驟 5:執行計畫並更新概況
    ↓
  (重複循環)

💡 實務建議:可以參考 NIST 提供的「社群概況(Community Profile)」,這是針對特定產業或情境預先建立的概況範本,例如製造業、醫療業等。


CSF 成熟度層級(Tiers):你的攤位等級

成熟度層級 用來描述組織資安風險治理與管理的嚴謹程度。

四個層級說明

層級 名稱 夜市比喻 特徵
Tier 1 部分的(Partial) 路邊攤,隨緣經營 沒有正式流程,靠經驗隨機應變
Tier 2 風險知情的(Risk Informed) 有固定攤位,開始有規矩 有風險意識但沒有全面落實
Tier 3 可重複的(Repeatable) 連鎖攤位,有 SOP 有正式政策且持續執行
Tier 4 自適應的(Adaptive) 品牌企業,持續進化 能即時應變、持續改善

⚠️ 注意:層級不是「分數」,不是每個組織都需要達到 Tier 4。應該根據組織的風險狀況與成本效益來選擇適當的層級。


NIST CSF 與 SSDF 的關係:從「經營攤位」到「製作滷汁」

前面我們用「經營夜市攤位」來比喻 NIST CSF,它關注的是整體營運的資安

但如果你是自己開發滷汁配方的攤販呢?這時候就需要另一套指南——NIST SSDF(Secure Software Development Framework,安全軟體開發框架)

兩者的比較

面向 NIST CSF 2.0 NIST SSDF 1.1
關注焦點 組織整體的資安風險管理 軟體開發過程的安全性
適用對象 所有組織 軟體開發者、採購者
比喻 經營攤位的守則 製作滷汁的配方安全
主要架構 6 大功能 4 大實務群組

SSDF 的四大實務群組

群組 代碼 說明 與 CSF 的關聯
準備組織 PO 確保人員、流程、技術準備好進行安全開發 對應 GOVERN、IDENTIFY
保護軟體 PS 保護程式碼不被竄改或未授權存取 對應 PROTECT
產出安全軟體 PW 在開發過程中減少弱點 對應 PROTECT
回應弱點 RV 識別並修復已發布軟體的弱點 對應 DETECT、RESPOND、RECOVER

在 CSF 中如何整合 SSDF?

CSF 2.0 的 PR.PS-06 子類別明確提到:

「安全軟體開發實務已整合,且其效能在整個軟體開發生命週期中受到監控。」

這表示如果你的組織有開發軟體,應該:

  1. GOVERN 階段:將安全開發納入組織政策
  2. IDENTIFY 階段:識別開發環境中的風險
  3. PROTECT 階段:實施 SSDF 的安全開發實務
  4. DETECT 階段:監控軟體弱點
  5. RESPOND/RECOVER 階段:處理已發現的弱點

實務整合範例

假設你是一家金融科技公司,同時需要:

┌─────────────────────────────────────────────────┐
│                 企業層級(CSF)                  │
│  ┌─────────────────────────────────────────┐   │
│  │            組織資安治理 (GV)              │   │
│  │  - 董事會資安責任                         │   │
│  │  - 資安政策制定                           │   │
│  │  - 供應鏈風險管理                         │   │
│  └─────────────────────────────────────────┘   │
│                       │                         │
│  ┌────────────────────▼────────────────────┐   │
│  │         開發團隊層級(SSDF)             │   │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐   │   │
│  │  │ 準備組織 │ │ 保護軟體 │ │產出安全 │   │   │
│  │  │   (PO)  │ │   (PS)  │ │軟體(PW) │   │   │
│  │  └─────────┘ └─────────┘ └─────────┘   │   │
│  │              ┌─────────┐               │   │
│  │              │回應弱點 │               │   │
│  │              │  (RV)   │               │   │
│  │              └─────────┘               │   │
│  └─────────────────────────────────────────┘   │
└─────────────────────────────────────────────────┘

如何開始使用 NIST CSF?

給新手的起步建議

第一步:了解組織現況

  • 你們有哪些重要的數位資產?
  • 目前有什麼資安措施?
  • 過去發生過什麼資安事件?

第二步:選擇適合的起點

組織類型 建議起點
小型企業、新創 從 NIST 的「小型企業快速入門指南」開始
有基礎資安措施 建立現況概況,找出差距
已有成熟資安 用 CSF 2.0 重新檢視,特別是 GOVERN 功能

第三步:善用 NIST 資源

NIST 提供許多免費資源:

  • 快速入門指南(QSG):針對特定主題的簡短指引
  • 資訊參考(Informative References):與其他標準的對照表
  • 實作範例(Implementation Examples):具體的實作建議
  • 社群概況(Community Profiles):產業別的概況範本

🔗 資源連結NIST CSF 官方網站


常見問題 FAQ

Q1:NIST CSF 是強制性的嗎?

A:對美國聯邦機構有強制性,但對一般企業是自願採用。不過,許多產業法規(如金融業、醫療業)會參考或要求遵循 CSF。

Q2:我們公司很小,也需要用 CSF 嗎?

A:CSF 設計上適用於任何規模的組織。小公司可以從核心的成果開始,選擇最相關的項目實施。

Q3:CSF 和 ISO 27001 有什麼不同?

A 面向 NIST CSF ISO 27001
類型 框架(Framework) 標準(Standard)
認證 無正式認證 可取得認證
費用 免費 需購買標準文件
彈性 較高 有明確要求

許多組織會同時使用兩者,用 CSF 做策略規劃,用 ISO 27001 做驗證。

Q4:從 CSF 1.1 升級到 2.0 要注意什麼?

A:主要變化包括:

  • 新增 GOVERN 功能
  • 強化供應鏈風險管理
  • 更新子類別編號(部分有變動)
  • 新增線上工具與資源

NIST 有提供升級指南,建議詳細閱讀。


結語:資安是一趟旅程,不是終點

NIST CSF 不是一份勾選完就結束的清單,而是一套持續改善的方法論。

就像夜市攤販不會因為今天生意好就停止進步,你的組織資安也需要:

  • 📊 定期評估現況
  • 🎯 設定合理目標
  • 🔄 持續改善流程
  • 👥 全員參與投入

從今天開始,用 NIST CSF 的思維來看待你的組織資安吧!


延伸閱讀

[NIST] 001 軟體開發也要穿防彈衣?一次搞懂 NIST SSDF 安全開發框架

「寫程式就寫程式,還要管什麼資安?」如果你還這樣想,那可能要小心了!現在的軟體開發,沒有做好安全防護,就像開店沒裝監視器一樣危險。今天就用最生活化的方式,帶你認識 NIST SSDF(安全軟體開發框架)


什麼是 NIST SSDF?用便當店來解釋!

想像你要開一間便當店,你不會只顧著炒菜,對吧?你還需要:

  • 👨‍🍳 訓練員工 怎麼安全使用刀具和瓦斯
  • 🔒 保護食材 不被偷或污染
  • 🍱 確保便當品質 衛生又好吃
  • 📞 處理客訴 萬一有人吃壞肚子要怎麼辦

NIST SSDF 就是把這套邏輯用在軟體開發上!它是由美國國家標準暨技術研究院(NIST)發布的 SP 800-218 文件,告訴你怎麼從頭到尾把軟體寫得「安全」。

SSDF 的核心精神:左移(Shift Left)

傳統做法是寫完程式再找漏洞,就像便當做好才檢查有沒有蟑螂 🪳(已經太晚了!)

左移的概念是:越早處理安全問題,成本越低。就像買菜時就挑新鮮的,比煮完發現爛掉好太多了!


SSDF 四大實務領域:用便當店來比喻

SSDF 把安全開發分成四大區塊,我們繼續用便當店來解釋:

🏢 PO(Prepare the Organization):準備好你的組織

便當店版本: 開店前的準備工作

SSDF 任務 便當店對照
PO.1 定義安全需求 制定食材採購標準、衛生規範
PO.2 建立角色與責任 誰負責採購?誰負責烹飪?誰負責清潔?
PO.3 導入工具鏈 買冰箱、裝抽油煙機、設置監視器
PO.4 定義安全檢查標準 什麼溫度叫「熟了」?什麼狀態叫「新鮮」?
PO.5 維護安全環境 廚房要乾淨、倉庫要上鎖、員工入口要刷卡

程式開發實例:

✅ 制定安全編碼規範(Coding Standard)
✅ 指派資安負責人(Security Champion)
✅ 導入 SAST/DAST 工具
✅ 設定 CI/CD Pipeline 的安全檢查點
✅ 開發環境與正式環境要隔離

🔐 PS(Protect the Software):保護你的軟體

便當店版本: 保護你的食材和配方

SSDF 任務 便當店對照
PS.1 保護程式碼 祖傳滷肉飯配方要鎖在保險箱
PS.2 提供完整性驗證 便當貼上防拆封貼紙
PS.3 保存發布紀錄 記錄每批食材的來源和日期(溯源)

程式開發實例:

✅ 程式碼存放在私有 Git Repository
✅ 使用 Code Signing 簽署發布檔案
✅ 產生 SBOM(軟體物料清單)
✅ 保存每次 Release 的完整紀錄

什麼是 SBOM?

就像便當的成分標示一樣!SBOM 會列出軟體裡用了哪些套件、版本是什麼,萬一某個套件出事,你可以馬上知道自己有沒有用到。


⚙️ PW(Produce Well-Secured Software):生產安全的軟體

便當店版本: 做出安全好吃的便當

SSDF 任務 便當店對照
PW.1 安全設計 菜單設計考慮過敏原、熱量標示
PW.2 設計審查 試菜會議,確認口味和安全
PW.4 重複使用安全元件 用經過認證的醬料,不要自己亂調
PW.5 遵循安全編碼實務 按照 SOP 烹飪,不亂加料
PW.6 安全配置編譯工具 確保瓦斯爐、烤箱設定正確
PW.7 程式碼審查 主廚試吃確認品質
PW.8 測試執行檔 出餐前最後檢查
PW.9 預設安全設定 便當預設少油少鹽(健康優先)

程式開發實例:

✅ 做威脅建模(Threat Modeling)
✅ 使用經過驗證的加密函式庫
✅ 執行 Code Review
✅ 跑 SAST(靜態掃描)和 DAST(動態掃描)
✅ 輸入驗證、輸出編碼
✅ 預設啟用 HTTPS、停用 Debug 模式

小提醒:常見的安全編碼原則

原則 說明 便當店比喻
輸入驗證 檢查使用者輸入的資料 確認客人點的餐真的有在菜單上
輸出編碼 避免 XSS 攻擊 便當盒要密封好,湯汁不能亂灑
最小權限 只給必要的權限 洗碗工不需要進金庫
錯誤處理 優雅地處理錯誤 賣完了就說「售完」,不要讓客人看到後廚在吵架

🚨 RV(Respond to Vulnerabilities):回應漏洞

便當店版本: 客訴處理與危機應變

SSDF 任務 便當店對照
RV.1 持續辨識漏洞 定期檢查食材有沒有過期
RV.2 評估與修復漏洞 客人說太鹹,調整食譜
RV.3 分析根本原因 為什麼會太鹹?是廚師手抖還是鹽巴受潮?

程式開發實例:

✅ 建立漏洞通報管道(VDP)
✅ 訂閱 CVE 資料庫更新
✅ 定期執行弱點掃描
✅ 建立 PSIRT(產品安全事件應變小組)
✅ 做 Root Cause Analysis(根因分析)

實際案例:從零開始導入 SSDF

假設你是一間新創公司的工程師,老闆說要導入 SSDF,你可以這樣做:

第一步:盤點現況(PO)

□ 公司有沒有安全編碼規範?
□ 有沒有人負責資安?
□ 開發環境和正式環境有隔離嗎?
□ 有在用什麼安全工具嗎?

第二步:保護程式碼(PS)

□ 程式碼是不是放在私有 Repository?
□ 有沒有做 Code Signing?
□ 知道專案用了哪些第三方套件嗎?

第三步:建立安全開發流程(PW)

□ 有沒有做威脅建模?
□ 有沒有執行 Code Review?
□ CI/CD 有跑安全掃描嗎?
□ 預設設定是安全的嗎?

第四步:準備回應機制(RV)

□ 外部人員發現漏洞怎麼通報?
□ 內部發現漏洞怎麼處理?
□ 有沒有做過資安演練?

SSDF 對照表:讓你一目瞭然

領域 代碼 中文名稱 核心問題
準備組織 PO Prepare the Organization 「開工前準備好了嗎?」
保護軟體 PS Protect the Software 「東西放好了嗎?」
生產安全軟體 PW Produce Well-Secured Software 「做得夠安全嗎?」
回應漏洞 RV Respond to Vulnerabilities 「出事怎麼辦?」

常見問題 FAQ

Q1:SSDF 是強制性的嗎?

對於一般企業,SSDF 是自願採用的最佳實務。但如果你要賣軟體給美國聯邦政府,根據行政命令 EO 14028,就需要符合 SSDF 的要求。

Q2:小公司也需要導入 SSDF 嗎?

SSDF 是可擴展的!你不需要一次做完所有項目。可以根據公司規模和風險程度,挑選最重要的項目先做。

Q3:SSDF 和 ISO 27001 有什麼不同?

框架 重點
SSDF 專注於軟體開發過程的安全
ISO 27001 整體資訊安全管理系統(涵蓋範圍更廣)

兩者可以互補,SSDF 可以作為 ISO 27001 在軟體開發領域的細部實作指南。

Q4:有什麼工具可以幫助導入 SSDF?

類別 工具範例
SAST(靜態掃描) SonarQube, Checkmarx, Fortify
DAST(動態掃描) OWASP ZAP, Burp Suite
SCA(軟體組成分析) Snyk, Dependabot, OWASP Dependency-Check
SBOM 產生 Syft, CycloneDX
秘密掃描 GitLeaks, TruffleHog

總結:讓安全成為習慣

NIST SSDF 不是要讓你的開發流程變得更複雜,而是要讓安全成為開發的一部分。就像便當店把衛生習慣內化到日常作業一樣,當安全變成習慣,就不會覺得麻煩了。

記住這四個關鍵字:

  1. 準備(PO):人員、流程、工具都要到位
  2. 保護(PS):程式碼和發布物要保護好
  3. 生產(PW):每個環節都要考慮安全
  4. 回應(RV):出問題要有應變能力

現在就開始檢視你的開發流程,看看哪些地方可以「左移」改善吧!


延伸閱讀