n8n-mcp 安全威胁模型解析:基于 STRIDE 框架的信任边界、资产清单与纵深防御设计
【免费下载链接】n8n-mcpA MCP for Claude Desktop / Claude Code / Windsurf / Cursor to build n8n workflows for you项目地址: https://gitcode.com/GitHub_Trending/n8/n8n-mcp
n8n-mcp 是一个将 AI 助手(Claude Desktop、Cursor、Codex 等)接入 n8n 节点文档与 n8n REST API 的 Model Context Protocol(MCP)服务器。本文以仓库内 docs/THREAT_MODEL.md 为主干,系统梳理该项目在 stdio、HTTP 单会话、多租户 HTTP 与 Docker 镜像四种部署形态下的威胁模型:哪些是项目明确承担的安全假设、四条信任边界如何划分、六大 STRIDE 威胁类别各由什么代码级缓解措施承接。读完本文,你将掌握该项目的安全设计全貌,并能据此判断自己的部署方式落在哪条信任边界之内、哪些能力由 n8n 本身负责、哪些加固项需要自行配置。
1. 威胁模型的定位与范围:安全边界在 n8n,而非 n8n-mcp
理解 n8n-mcp 威胁模型的第一步,是接受它的一个核心论断:"security boundary is n8n itself, not n8n-mcp"。正如 SECURITY.md 所声明的,n8n-mcp 是 n8n REST API 的代理——凡是能通过 n8n-mcp 执行的操作,用同一把 API Key 直接调用 n8n REST API 也能完成;n8n-mcp 不授予任何超出 n8n API 本身的能力。因此威胁模型明确把下列内容划在评估范围之外:
- n8n 自身的安全性:通过 n8n REST API 可达的能力(例如创建带 Code 节点的工作流)不在本模型内重新评估;
- LLM 固有的通用提示注入风险:任何 MCP 服务器都平等面对此类风险,并非 n8n-mcp 特有;
- AI 客户端自身的安全性:Claude Desktop、Cursor、Codex 等客户端的漏洞不在范围内。
模型覆盖的对象包括:n8n-mcp 服务器本身(所有受支持的部署模式:stdio、HTTP 单会话、多租户 HTTP、Docker 镜像)、AI 客户端与服务器、n8n 实例及 n8n.io 模板 API 之间的数据流,以及发布 npm 包与ghcr.io/czlonkowski/n8n-mcp容器镜像所依赖的供应链。
2. 三大安全目标(按优先级排序)
威胁模型为项目定义了三个安全目标,优先级从高到低:
- 凭据卫生(Credential hygiene):用户的
N8N_API_KEY、HTTPAUTH_TOKEN以及多租户模式下每个租户的凭据,必须始终停留在其被提交时所处的信任边界之内,不得越界(例如不得落盘、不得进入日志或错误响应)。 - 文档准确性(Accurate documentation):提供给 AI 客户端的节点/模板数据必须真实反映底层 n8n 目录,不能混入被注入的内容。
- 安全默认值(Safe defaults):开箱即用的配置应让两条最常见部署路径(Claude Desktop + stdio;带
AUTH_TOKEN的自托管 HTTP)默认就是安全的。
这三条目标直接对应后文资产清单与 STRIDE 分析中反复出现的缓解措施——尤其是"凭据不入日志、不落盘、按会话隔离"这一主线。
3. 系统分解:参与者、部署模式与信任边界
3.1 参与者(Actors)
| 参与者 | 描述 |
|---|---|
| 本地开发者 | 在 Claude Desktop / Cursor / Codex / VS Code 内以 stdio 模式运行服务器,与服务器共享进程信任边界 |
| 自托管运维者 | 直接或通过 Docker 运行 HTTP 服务器供自己使用,持有AUTH_TOKEN与N8N_API_KEY |
| 多租户租户 | 连接共享 HTTP 部署,通过请求头自带各自的 n8n 凭据 |
| AI 客户端 | 与服务器通信的 LLM 驱动 MCP 客户端。被视为"糊涂代理"(confused deputy)——它可能依据不可信的工作流文本行事 |
| 下游 n8n 实例 | 使用管理类工具时接收服务器发出的 REST API 调用 |
| n8n.io 模板 API | 仅出站访问的公开工作流模板来源 |
| 外部攻击者 | 未认证的网络攻击者,目标是暴露在公网的 HTTP 部署 |
| 恶意贡献者 | 提交精心构造的 PR 或接管维护者账号(供应链攻击) |
值得注意 "AI client" 被明确标注为 confused-deputy 型参与者:当 n8n 实例中存在可被恶意者修改的工作流(名称、描述、执行结果)时,这些内容会经服务器回显给 LLM,可能被用于操纵 AI 行为。这一风险在 docs/SECURITY_HARDENING.md 的 "Prompt Injection Awareness" 一节有进一步论述,缓解手段包括限制工作流的创建/修改权限、用DISABLED_TOOLS收窄可用工具面、在执行 AI 生成的工作流操作前人工复核。
3.2 部署模式
- stdio:由 AI 客户端拉起单进程,通过 stdin/stdout 通信,无网络暴露面;
- HTTP 单会话(single-session):Express 服务器,共用一个
AUTH_TOKEN,会话状态保存在内存中; - 多租户 HTTP:通过
ENABLE_MULTI_TENANT=true开启,每个请求在请求头中携带租户的 n8n URL 与 API Key(x-n8n-url、x-n8n-key、x-instance-id、x-session-id); - Docker 镜像:
ghcr.io/czlonkowski/n8n-mcp,以构建期生成的随机 UID/GID 非 root 用户运行。
3.3 信任边界(Trust Boundaries)
- 进程边界(stdio):AI 客户端与服务器共享同一信任级别——任何能启动该二进制文件的进程都可以从环境中读取
N8N_API_KEY。这是 stdio 传输的固有威胁模型,服务器不做额外防御。 - 网络边界(HTTP):
AUTH_TOKEN门禁是唯一认证器,其后的所有内容都处于服务器信任区内。 - 每会话边界(多租户):
x-instance-id/x-session-id请求头将会话状态与该请求工具调用所用的 n8n 凭据绑定起来。 - 出站边界:对已配置 n8n REST API 与
api.n8n.io的调用离开服务器进程,其信任程度等同于其 TLS 端点的可信程度。
3.4 数据流图(Data-flow Diagram)
原文档给出的 mermaid 数据流图完整呈现了各信任区之间的流转关系:
图中几个关键事实与源码一一对应:nodes.db/templates.db在运行时只读(Dockerfile 在构建期将数据库烘焙进镜像,见 Dockerfile);SESS(内存会话状态)在多租户模式下承载租户凭据,其生命周期受会话 TTL 约束;npm 与 ghcr 通过供应链虚线进入服务器信任区。
4. 资产清单(Assets)
| 资产 | 敏感度 | 说明 |
|---|---|---|
AUTH_TOKEN | 高 | HTTP 模式的唯一门禁,每次部署独立生成(见 docs/SECURITY_HARDENING.md) |
N8N_API_KEY(及多租户等价物) | 高 | 对目标 n8n 拥有完整的工作流与凭据读写权限 |
| 内存会话状态 | 中 | 保存每会话上下文;多租户模式下在会话生命周期内持有租户的 n8n 凭据 |
data/nodes.db | 低 | 公开的 n8n 节点文档,无用户数据 |
data/templates.db | 低 | 公开的 n8n.io 工作流模板 |
npm 包n8n-mcp | 高 | 下游用户直接执行,完整性至关重要 |
Docker 镜像ghcr.io/czlonkowski/n8n-mcp | 高 | 同上——用户拉取并运行 |
敏感度分级直接决定了缓解投入:低敏感度资产(两个数据库)只需保证只读与防篡改,而高敏感度资产(两类凭据、发布物)需要常时比较、限流、轮换、非 root 容器等多重控制。
5. STRIDE 分析:六类威胁与代码级缓解
以下每小节把一类 STRIDE 威胁与代码库中当前落实的具体缓解措施配对,并给出对应源码路径。
5.1 Spoofing(伪造)
威胁:窃取AUTH_TOKEN冒充合法 HTTP 客户端。缓解手段有三层:
- 常时比较(constant-time comparison):
AuthManager.timingSafeCompare使用crypto.timingSafeEqual逐字节比较,避免因长度/内容差异引入可被时序分析利用的旁路。实现见 src/utils/auth.ts,配套的buildBearerChallenge按 RFC 6750);单元测试见 tests/unit/utils/auth-timing-safe.test.ts。 - 基于 IP 的认证失败限流:
express-rate-limit限流器应用在认证端点,默认窗口 15 分钟(AUTH_RATE_LIMIT_WINDOW,默认 900000ms)、每 IP 最多 20 次(AUTH_RATE_LIMIT_MAX),并开启RateLimit-*标准响应头;skipSuccessfulRequests使其只统计失败的认证尝试(见 src/http-server-single-session.ts)。限流同样覆盖GET /mcp、DELETE /mcp、GET /sse、POST /messages等全部需要认证的路由。 - 部署加固指引:
openssl rand -base64 32生成令牌并按季度轮换(见 docs/SECURITY_HARDENING.md)。另外服务器启动时会对默认占位令牌做强校验:NODE_ENV=production下若仍使用默认AUTH_TOKEN会直接拒绝启动(见 src/http-server-single-session.ts)。
威胁:多租户模式下的租户请求头伪造。缓解:基于空原型(null-prototype)映射的会话级隔离——transports、servers、sessionMetadata、sessionContexts四个容器全部用Object.create(null)创建(见 src/http-server-single-session.ts),凭据按请求绑定,任何租户密钥都不会在会话 TTL 之外持久化。同时,多租户模式下x-n8n-url与x-n8n-key必须成对出现,缺任一即拒绝请求(见 src/http-server-single-session.ts)。
威胁:stdio 模式下冒充受信任的 MCP 客户端。明确不做防御——这依赖进程/文件系统信任边界,与 stdio 传输的威胁模型一致(启动服务器的调用方本身已被信任)。
5.2 Tampering(篡改)
威胁:来自api.n8n.io的恶意工作流 JSON。缓解:模板作为惰性数据存储并通过 JSON 校验;n8n-mcp 内部从不eval、require或执行这些模板。任何执行都发生在用户自己的 n8n 实例上,属于 SECURITY.md 界定的范围外。
威胁:静态篡改nodes.db/templates.db。缓解:两个数据库在运行时按只读对待,通过npm run rebuild/npm run fetch:templates重建;Docker 镜像在构建期将数据库烘焙进镜像(Dockerfile),运行时不会重新生成。
威胁:中间人篡改 n8n REST 流量。缓解:服务器始终通过已配置的 HTTPS URL 调用 n8n,证书校验交给 Node 默认 TLS 栈;docs/SECURITY_HARDENING.md 明确警告:除本地开发外不得使用明文http://目标。
5.3 Repudiation(抵赖)
威胁:HTTP 模式下否认执行过特权操作。缓解:通过 src/utils/logger.ts 记录请求与工具调用日志,HTTP 访问日志包含会话标识与工具名,使运维者能够追溯行为归属。
stdio 模式按设计没有外部审计线索——传输对调用方是本地的,审计职责委托给 AI 客户端。
5.4 Information disclosure(信息泄露)
威胁:N8N_API_KEY或AUTH_TOKEN经日志或错误消息泄露。缓解分三层:
- 日志侧脱敏:src/utils/redaction.ts 提供
redactHeaders,将authorization、proxy-authorization、cookie、set-cookie、x-n8n-key、x-n8n-url等敏感头的值替换为[REDACTED]占位符;summarizeMcpBody/summarizeToolCallArgs只记录方法名、参数键列表与序列化大小,绝不记录参数值。POST /mcp 的认证后日志即以这些函数脱敏(见 src/http-server-single-session.ts)。 - 错误响应侧脱敏:
sanitizeErrorForClient在生产环境把异常映射为通用错误码(AUTH_ERROR、SESSION_ERROR、VALIDATION_ERROR、INTERNAL_ERROR),堆栈只进日志不进响应(见 src/http-server-single-session.ts)。 - 健康检查端点最小化:
GET /health故意不暴露会话 ID、令牌元数据、内存统计等运营敏感信息,只返回 status/version/uptime/timestamp(见 src/http-server-single-session.ts)。
威胁:用户工作流中硬编码的密钥被回显给 LLM。缓解:n8n_audit_instance工具在审计时调用 src/services/credential-scanner.ts 扫描工作流中的硬编码密钥,覆盖 50+ 种服务特定密钥前缀(OpenAI、Anthropic、AWS、GitHub、Slack、Stripe、SendGrid 等)加通用 PII 模式;关键设计是检测结果中永不出现原始密钥值——maskSecret在扫描时即脱敏,只保留首 6 尾 4 字符(见 src/services/credential-scanner.ts),并以"发现项"而非"原样回显"的方式呈现给调用方。测试见 tests/unit/services/credential-scanner.test.ts。
威胁:经由冗长堆栈跟踪泄露内部状态。缓解:handler 级 try/catch 包装把服务端异常转换为脱敏的 MCP 错误;堆栈保留在日志中而非响应中(与上述sanitizeErrorForClient同一机制)。
5.5 Denial of service(拒绝服务)
威胁:对 HTTP 认证端点的暴力破解。缓解:认证端点的express-rate-limit限流器(默认 20 次/15 分钟/IP),已在上文 Spoofing 节详述;对应测试覆盖于 tests/unit/http-server/ssrf-gate.test.ts 等 HTTP 层测试中。
威胁:多租户模式下会话无界增长。缓解:可配置的N8N_MCP_MAX_SESSIONS上限(默认 100,见 src/http-server-single-session.ts),以及按SESSION_TIMEOUT_MINUTES(默认 30 分钟)周期性清理空闲会话——清理循环每 5 分钟运行一次,同时回收孤儿会话上下文(见 src/http-server-single-session.ts)。达到上限时新initialize请求返回 429。
威胁:滥用出站模板抓取。缓解:模板抓取发生在重建(rebuild)期间而非每次请求,并遵守 n8n.io API 的速率限制。
5.6 Elevation of privilege(权限提升)
威胁:多租户 HTTP 部署中的跨租户串扰。缓解:会话作用域映射使用Object.create(null)规避原型污染(恶意 session ID 如__proto__、constructor无法写入Object.prototype,代码注释明确记录了这一考量,见 src/http-server-single-session.ts);每个会话在请求时从自身请求头解析 n8n 凭据,而非共享全局N8N_API_KEY。
威胁:经精心构造的载荷进行原型污染升级。缓解:除上述空原型映射外,配置输入还经过 Zod schema 校验——src/config/n8n-api.ts 对N8N_API_URL、N8N_API_KEY、超时与重试次数等做类型/格式校验,多租户的实例上下文同样有validateInstanceContext把关(请求头上下文不合法即失败关闭,见 src/http-server-single-session.ts)。
威胁:容器逃逸到宿主机。缓解:发布的 Docker 镜像以构建期随机 UID/GID 创建的非 root 用户运行,USER nodejs在CMD前显式降权(见 Dockerfile)。
威胁:下游 n8n 上的能力放大(如 Code 节点执行)。明确划出范围外:按 SECURITY.md,n8n-mcp 不授予调用方在 n8n REST API 上本不具备的任何能力。若担心 Code 节点,应在 n8n 侧配置 Code 节点沙箱、N8N_CODE_NODE_ALLOWED_MODULES或企业版 RBAC,详见 docs/SECURITY_HARDENING.md。
5.7 出站 SSRF 防护(贯穿性控制)
虽然威胁模型正文把 SSRF 相关缓解分散在各 STRIDE 类别中,值得单独指出的是 src/utils/ssrf-protection.ts 实现的WEBHOOK_SECURITY_MODE门禁——它是项目对出站边界最重要的纵深控制:
- strict(默认):阻止 localhost、RFC1918 私网、其他不可全局路由的 IANA 特殊用途段(含
100.64.0.0/10共享地址空间、组播、广播),以及云元数据端点; - moderate:放行 localhost(如
http://localhost:5678),其余同 strict; - permissive:仅阻止云元数据——只适合 n8n-mcp 与 n8n 共处私有 Docker/Kubernetes 网络、或 n8n 仅在 CGNAT 段(如 Tailscale)可达的场景;
- 云元数据端点(169.254.169.254、metadata.google.internal 等)在所有模式下均被阻止。
实现细节体现了对抗 DNS rebinding 的工程投入:校验时先解析 DNS 得到实际 IP 再逐段匹配私网/元数据规则(见 src/utils/ssrf-protection.ts),并提供createPinnedAgents把后续连接固定到已校验的 IP 上(见 src/utils/ssrf-protection.ts);IPv6 侧覆盖了回环、链路本地、ULA、组播以及 NAT64/6to4/Teredo 隧道中内嵌私网或元数据 IP 的绕行路径(见 src/utils/ssrf-protection.ts)。该门禁同时作用于 webhook 触发器 URL、N8N_API_URL与多租户x-n8n-url头来源的每请求 URL;测试见 tests/unit/utils/ssrf-protection.test.ts。
6. 开源 / 依赖库特定威胁(供应链)
这类威胁针对项目本身而非某个具体部署:
| 威胁 | 缓解 |
|---|---|
| 维护者账号接管 | 维护者账号启用 2FA,main分支开启分支保护,所有 PR 需评审 |
| 恶意贡献者长期积累信任 | 代码评审、单维护者合并策略、发布版本签名 tag |
| npm 包名仿冒(typosquatting) | 以有辨识度的 scoped 名称发布;鼓励下游按版本或完整性哈希锁定依赖 |
| 传递依赖被攻陷 | Dependabot 告警、提交锁文件(lockfile)、CI 中运行npm audit |
| 发布流水线被攻陷 | 发布由 GitHub 托管 runner 以最小权限执行(仅 npm 与 ghcr 所需 scope),发布以绿色 CI 为前提 |
容器侧,镜像使用多阶段构建:构建阶段只装编译依赖,运行时阶段仅保留必要工具(curl、su-exec)并以--production安装运行依赖,进一步收窄了供应链攻击面(见 Dockerfile)。
7. 顶层风险与对应控制
| 资产 | 主要控制 |
|---|---|
AUTH_TOKEN | 常时比较、认证端点限流、部署指南强制轮换 |
N8N_API_KEY(及多租户等价物) | 永不落盘;限定在请求/会话内;从日志与错误响应中脱敏 |
| 多租户隔离 | 会话级状态、空原型映射、请求头派生凭据、会话 TTL 与上限 |
| 供应链(npm + ghcr) | 锁定依赖、CI 门禁发布、签名 tag、非 root 容器用户 |
8. 威胁模型复审触发条件
该威胁模型在以下任一情况发生时需要重新评审:
- 新增一个会变更下游 n8n 状态的 MCP 工具;
- 新增部署模式或传输方式(如 OAuth、WebSocket、托管变体);
- 发布大版本(major version);
- 系统引入新类别的凭据;
- 若无上述情况,至少每自然年评审一次。
9. 参考文献与延伸阅读
- SECURITY.md——漏洞披露政策与范围界定(in-scope / out-of-scope)
- docs/SECURITY_HARDENING.md——部署加固参数(
AUTH_TOKEN、DISABLED_TOOLS、WEBHOOK_SECURITY_MODE及 Code 节点能力限制) .github/INCIDENT_RESPONSE.md——事件响应流程(72 小时内确认、分级、修复并致谢报告者)- 微软官方 STRIDE 威胁建模参考:https://learn.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats
结语:安全默认值如何落在代码里
把威胁模型与源码对照后可以看出,n8n-mcp 的"安全默认值"并非口号,而是可验证的代码事实:HTTP 模式强制要求非默认AUTH_TOKEN(生产环境默认令牌直接拒绝启动)、认证端点默认限流、会话容器默认空原型、出站 URL 默认 strict 模式 SSRF 门禁、敏感信息默认脱敏后入日志、容器默认非 root 随机 UID/GID。理解这套模型后,运维者应重点自查两件事:一是自己的部署形态处于哪条信任边界(stdio 共享进程信任、HTTP 依赖AUTH_TOKEN、多租户依赖会话头隔离);二是超出 n8n-mcp 边界的能力(Code 节点执行、LLM 提示注入)需要在 n8n 实例与业务流程侧另行设防。
【免费下载链接】n8n-mcpA MCP for Claude Desktop / Claude Code / Windsurf / Cursor to build n8n workflows for you项目地址: https://gitcode.com/GitHub_Trending/n8/n8n-mcp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考