NSA 的 MCP 安全清单:边界、沙箱与签名消息

·阅读约13分钟·Evergreen Tools Team

2026 年 5 月 20 日,美国国家安全局(NSA)人工智能安全中心(AISC)发布了一份网络安全信息表(CSI):《Model Context Protocol (MCP):面向 AI 驱动自动化的安全设计考量》。这是美国国家安全机构发布的第一份针对 MCP 的正式安全指引。它的前提并不客气:MCP 已经成为跨 AI 驱动服务的「事实标准」,但它的快速扩散远超其安全模型的演进速度;而且这份协议反转了一个熟悉的交互模式——不是客户端向服务器请求数据,而是服务器常常要为连接的客户端查询甚至执行动作,于是产生了一批「尚未被充分追踪的新攻击路径」。如果你在生产环境里跑 MCP,这份文档值得逐条对照。

先划信任边界:智能体、插件、模型与用户不在同一个信任区

先划信任边界:智能体、插件、模型与用户不在同一个信任区

一、为什么要在现在严肃对待 MCP

文档的描述很直接:MCP 发布时采用了灵活且规格不足的设计,就像早期 Web 协议一样,给了实现者自由度,也带来了安全用法的模糊空间。风险已经不是理论——公共实验室与安全研究者发布了存在漏洞的 MCP 服务器实现,用以演示防护不足的 MCP 有多容易被利用;其中一类典型漏洞是任意代码执行(ACE),可被归入 CWE-77、CWE-78、CWE-94、CWE-95 等类别管理。文档还点名了一批部署 MCP 的产品(AutoGen Studio、Harvey AI、Agentverse、Copilot 等),并强调 MCP 已用于查询个人可识别信息这类敏感任务。它给出的结论是:安全默认行为必须通过实现严谨性、编码实践、更清晰的协议规格与更健壮的验证工具来强制达成——也就是说,别指望协议替你安全。

# 1. Design for boundaries: put tools in data classification zones
trust_zones:
  public:
    tools: [weather_lookup, public_docs_search]
    data: public
  internal:
    tools: [ticket_search, deploy_status]
    data: internal
  regulated:
    tools: [ehr_query, payment_ledger]
    data: regulated
    runtime: local                        # prefer a local MCP server
    approval: human_in_the_loop

rules:
  - user_facing_plugin_output: never_passes_to_privileged_backend_unchecked
  - dynamic_tool_discovery: require_origin_verification_or_authorization

二、先划边界:信任分区与数据分级

第一条建议是「为边界而设计」。组织需要明确定义 MCP 各组件之间的信任边界,包括智能体、插件、模型与最终用户,把它们视为处在不同信任区,各自有其假设与控制。一个具体例子:来自面向用户插件的数据,不应被特权后端模型盲目接受。第二条是谨慎对待动态工具发现——这是 MCP 灵活性的标志,除非能配合来源验证或授权检查。第三条是可操作策略:把工具与模型按数据分级分区对齐,公开数据集用公开工具,涉及敏感或受监管信息(国家安全信息、受控非密信息、健康记录、金融信息等)的工具则必须显式控制与隔离;处理私有数据时优先使用本地 MCP 服务器实例,以降低数据外泄风险。最后,文档建议用过滤型的出网代理(如 Squid、tinyproxy)或企业级数据防泄漏(DLP)方案约束对外连接的目标 URL 与访问方式。

// 2. Validate parameters against schema, range, AND execution context
import Ajv from "ajv";
import { execContext } from "./runtime";

const ajv = new Ajv({ allErrors: true });

function validateInvocation(tool, args, caller) {
  const schema = tool.inputSchema;
  if (!ajv.validate(schema, args)) {
    throw new Error("schema violation: " + JSON.stringify(ajv.errors));
  }
  if (!tool.allowedContexts.includes(execContext.name)) {
    throw new Error("context mismatch: refusing to execute in " + execContext.name);
  }
  if (caller.isUserSupplied && !tool.allowsParameterForwarding) {
    // NSA guidance: parameter forwarding should be blocked or restricted when
    // the source of the data is ambiguous or potentially user-supplied.
    throw new Error("ambiguous origin: forwarding blocked");
  }
  return true;
}
在被约束之前,每一次工具调用都是高风险动作

在被约束之前,每一次工具调用都是高风险动作

三、校验参数,约束并沙箱化执行

文档对「参数校验」的定义比通常理解更宽:不仅校验输入,还要理解执行环境的上下文与配置。它举了一个很有说服力的例子——在一个连接 MCP 的数学解释器里,攻击者可以操纵 context 参数触发非预期的文件 I/O,而数学输入输出本身看起来完全正常。因此每一次工具调用或模型执行请求,都必须按明确定义的 schema、预期取值范围以及数据将被处理的上下文来校验,包括畸形输入、缺失字段与超大体积。文档还要求:当数据来源含糊或可能由用户提供时,参数转发应被显式阻止或限制,否则为某个组件准备的输入会级联污染下游。执行侧则更硬:任何经由 MCP 触发的工具执行都应被当作潜在高风险动作,要用操作系统级框架隔离每个工具的执行上下文——Windows 的 AppContainer,以及 seccomp、AppArmor、SELinux——并遵循最小权限:服务器不需要访问的敏感文件系统、模型或数据文件、内网路径,应在运行时显式拒绝。

# 3. Constrain and sandbox tool execution (one sandbox per tool)
#    OS-level isolation examples from the CSI: AppContainer (Windows),
#    seccomp, AppArmor, SELinux.
services:
  mcp-tool-filesystem:
    image: internal/mcp-tool-fs:1.4.0
    read_only: true
    security_opt:
      - no-new-privileges:true
      - apparmor:docker-default
    cap_drop: [ALL]
    network_mode: none                  # deny by default, add nothing back
    volumes:
      - /srv/workspaces/agent-42:/workspace:rw
    tmpfs:
      - /tmp:size=64m
# Least privilege: if a server does not need a sensitive filesystem, model or
# data file, or an internal network, deny that path at runtime.

四、签名并校验消息:把完整性当默认前提

文档提醒:消息的真实性与机密性不应被视为理所当然,尤其是在处理敏感数据或做安全关键决策时。MCP 目前依赖传输层加密(如 TLS),但协议本身既无法强制或验证加密,也不感知消息完整性。它的建议是利用现代密码库在 JSON 载荷内部直接加入签名,用以保护敏感消息;需要时会话级保护可加入有时限的签名。更进一步,MCP 消息应当包含过期时间戳与重放保护元数据,以防延迟投递或重复投递——在分布式与事件驱动系统中这是已知风险;文档还指出 OWASP 应用安全验证标准(ASVS)V7「会话管理」的建议在这里可以直接套用:请求应当被密码学地绑定到时间与上下文,以避免篡改、故意的重放以及非预期的重复执行。

# 4. Sign MCP messages and bind them to time and context
import hmac, hashlib, json, time, secrets

SIGNING_KEY = b"...from-key-vault-not-from-env..."
SEEN_NONCES = set()
MAX_SKEW_S = 30

def sign_message(payload: dict) -> dict:
    envelope = {
        "payload": payload,
        "iat": int(time.time()),
        "exp": int(time.time()) + MAX_SKEW_S,
        "nonce": secrets.token_urlsafe(16),      # replay protection
        "aud": "mcp-server-inventory",           # bind to the intended receiver
    }
    body = json.dumps(envelope, sort_keys=True, separators=(",", ":"))
    envelope["sig"] = hmac.new(SIGNING_KEY, body.encode(), hashlib.sha256).hexdigest()
    return envelope

def verify_message(envelope: dict) -> bool:
    body = json.dumps({k: envelope[k] for k in ("payload", "iat", "exp", "nonce", "aud")},
                      sort_keys=True, separators=(",", ":"))
    expected = hmac.new(SIGNING_KEY, body.encode(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, envelope["sig"]):
        return False
    if envelope["exp"] < time.time() or envelope["nonce"] in SEEN_NONCES:
        return False
    SEEN_NONCES.add(envelope["nonce"])
    return True

# The CSI recommends signatures inside the JSON payload, plus expiration
# timestamps and replay-protection metadata; OWASP ASVS V7 session management
# is directly applicable.
记录参数、身份与结果哈希

记录参数、身份与结果哈希

五、过滤输出、记录一切、跟踪漏洞

文档把「输出」也算作不可信输入:即使输出来自先前已审查的组件,也必须被视为下一阶段管道的不可信输入并接受检查。过滤手段包括内容长度检查、违禁关键词扫描、限流与应用特定的策略执行;关键点在于 LLM 与智能体常会生成看起来无害、却携带隐藏逻辑或提示操纵的文本,因此输出过滤要能检测间接提示注入或工具链转向的尝试;在多组件管道中,这意味着逐跳记录并检查每个 MCP 工具的输出。可观测性方面,文档要求记录所有工具与模型调用,包括精确参数、涉及的身份,以及在可行时记录结果或输出的密码学哈希,并把这些遥测接入组织既有的 SIEM 或合规看板;同时建立跟踪 MCP 相关漏洞的正式流程。最后一句提醒很务实:感知 MCP 的安全代理仍然有限且尚在成熟,可能提供部分缓解,但鉴于其早期阶段,尤其在处理敏感数据时应谨慎使用。

# 5. Treat every output as untrusted input to the next hop
def inspect_output(tool_name, output, expected_schema, limits):
    findings = []
    if len(output) > limits.max_bytes:
        findings.append("oversized_output")
    for pattern in limits.injection_signals:
        if pattern.search(output):
            findings.append("possible_indirect_prompt_injection")
    if not schema_ok(output, expected_schema):
        findings.append("schema_violation")

    log_event({
        "tool": tool_name,
        "params_hash": sha256(canonical(args)),   # exact parameters, hashed
        "identity": caller_identity,               # who invoked it
        "result_hash": sha256(output),             # hash of the result
        "findings": findings,
        "sink": "siem",
    })
    return {"forward": not findings, "findings": findings}

📌 常见问题 FAQ

这份 NSA MCP 安全指引是什么?

是 NSA 人工智能安全中心(AISC)于 2026 年 5 月发布的网络安全信息表《Model Context Protocol (MCP): Security Design Considerations for AI-Driven Automation》(编号 U/OO/6030316-26、PP-26-1834,May 2026 Ver. 1.0),官方新闻稿日期为 2026 年 5 月 20 日。

为什么 NSA 认为 MCP 需要专门的安全指引?

文档指出:MCP 已成为跨 AI 驱动服务的事实标准,但快速扩散已超越其安全模型的发展;协议反转了传统客户端—服务器模式,服务器常需为客户端查询甚至执行动作,由此产生新的、追踪不足的攻击路径,既有的网络防御策略不足以应对。

映射到 CWE 的典型风险是什么?

文档提到任意代码执行(ACE)这一类高严重性漏洞,常见于用户提供的逻辑或代码被执行的 MCP 环境,通常按 CWE-77、CWE-78、CWE-94、CWE-95 等类别进行漏洞管理。

消息签名具体怎么做?

文档建议在 JSON 载荷内部加入密码学签名以保护敏感消息,必要时加入有时限的签名,并让消息带过期时间戳与重放保护元数据,把请求绑定到时间与上下文;OWASP ASVS V7 会话管理的建议可直接参考。

MCP 感知的安全代理可以用吗?

文档态度是谨慎:这类代理仍然有限且处于成熟早期,可能提供部分缓解,但在处理敏感数据时应谨慎使用,不能替代边界设计、参数校验与执行沙箱等基础控制。