ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

n8n 安全加固指南:从未授权访问到 SSRF 的漏洞与防御

n8n 安全加固指南:从未授权访问到 SSRF 的漏洞与防御

最近团队内部做了一次安全巡检,发现不少同事都在用 n8n 搭自动化流程,从抓取运营数据到同步客户信息,再到定时触发各类通知,确实方便。但很少有人意识到,n8n 这类工作流引擎一旦暴露在公网,攻击面比普通 Web 应用要大得多——它不仅能访问你的数据库,还能以你的身份调用各种第三方服务。这篇文章我把 n8n 从部署到使用的常见高危漏洞做了个系统性梳理,结合一些实际踩过的坑,说清楚攻击者是怎么打进来的,以及我们该怎么挡住。

1. 核心思路:先把 n8n 的暴露面和资产价值聊透

1.1 为什么 n8n 会成为攻击目标

n8n 本身是一款开源的工作流自动化平台,靠可视化节点编排把不同的系统串起来。你可以用它连接数据库、HTTP API、消息队列、云服务,甚至直接在节点里写 JavaScript 脚本做数据加工。正是因为这种"连一切"的能力,n8n 实例在攻击者眼里就是一座金矿。

从资产价值的角度看,一个 n8n 实例通常能接触到几类高价值数据:

  • 各种第三方服务的 API Key 和 Secret(存在 n8n 的凭证存储里)
  • 数据库连接字符串和访问凭据
  • 内部系统的 HTTP 接口地址和认证信息
  • 工作流中流转的业务数据(订单、用户信息、日志等)

我见过不少团队把 n8n 部署在云服务器上,直接用默认端口 5678 对外提供服务,连基本的基础认证都没开。这就像把公司仓库的钥匙挂在门口,路过的人都能顺手拿走。n8n 默认装完只有一个随机生成的邀请链接,很多人为了省事干脆把邀请链接关掉,结果整个平台变成完全开放的状态,任何知道地址的人都能注册账号、创建工作流、读写凭证。

1.2 梳理攻击面:从入口到数据出口

想做好防御,得先搞清楚 n8n 的完整攻击路径。我习惯把攻击面分成三层来看:

第一层是入口层。包括 n8n 的 Web 界面、REST API、Webhook 触发端点。这一层的风险主要是未授权访问、弱认证、Webhook 被滥用来触发恶意工作流。

第二层是执行层。也就是工作流运行时。攻击者如果能控制工作流的某些输入,比如 Webhook 传来的数据,就有可能利用节点配置里的注入点,执行恶意代码、发起恶意的 HTTP 请求(SSRF),或者读取运行环境里的敏感文件。

第三层是数据层。包括凭证存储、数据库、日志。这一层一旦被攻破,攻击者可以提取所有集成的账号凭据,然后拿着这些凭据去访问你的核心业务系统。

攻击面梳理清楚了,防御才有针对性。下面我按照漏洞的实际危害程度逐类拆解。

2. 高危漏洞拆解:原理、利用方式与影响范围

2.1 未授权访问与弱认证绕过

漏洞原理

n8n 在默认配置下有两种访问模式:一种是开放注册模式,任何访问者都能创建账户;另一种是基础认证模式,通过环境变量N8N_BASIC_AUTH_USER和N8N_BASIC_AUTH_PASSWORD控制,但基础认证本身只对 UI 界面和 API 请求做一层很薄的保护,一旦凭据泄露或被暴力破解,攻击者就获得了完整的管理员权限。

实际案例分析:某团队在测试环境部署了 n8n,开启了基础认证,但密码设置成了 "n8n123",随后对公网开放了 5678 端口。结果被扫描器命中,攻击者用默认字典几分钟就猜出了密码。进入后台后,攻击者拿到工作流里配置的数据库凭据和对象存储 Key,随后在内网横向移动,最终影响到生产环境的数据库访问权限。

利用路径

攻击者扫描公网 IP 的 5678 端口,发现 n8n 的登录页面后,先尝试默认凭据,再用常见弱密码字典爆破。一旦登进去,直接导出所有凭证列表,或者新建一个 Webhook 工作流指向内网管理接口。

修复和预防

  • 生产环境必须启用更强的认证机制。n8n 官方支持配置外部身份验证(比如 OAuth2、LDAP),有条件就直接上企业 SSO 集成。
  • 禁用基于密码的基础认证,改用带双重验证的登录方式。
  • 如果必须用基础认证,密码要使用高熵随机串,长度至少 20 位,并且在反向代理层面额外加一道 IP 白名单。

提示:基础认证不是银弹。它只拦截浏览器页面的正常请求,攻击者完全可以绕过前置代理直接访问 n8n 端口,所以基础认证一定要和网络层隔离配合使用。

2.2 服务端请求伪造(SSRF)——最危险的一类

漏洞原理

n8n 的核心能力之一就是 HTTP Request 节点,允许用户自定义 URL、请求方法、请求头、请求体。这个节点的设计初衷是让工作流去调用外部 API,但如果没有控制好目标地址的范围,用户就可以把请求发给任何地址,包括云服务器的元数据服务地址、内网的管理端口、容器网络的兄弟节点地址。

实际利用场景

我在一次授权渗透测试里做过验证:目标 n8n 部署在云服务器上,工作流里有一个 HTTP Request 节点,输入参数直接拼接到 URL 里。我通过 Webhook 传入一个内网地址,这个节点发起请求,返回了内部系统的响应内容。接着用同样的方法访问云厂商的元数据接口,拿到了临时凭据,然后直接在目标账号的存储桶里列出了所有文件清单。

影响范围

SSRF 的影响程度取决于运行 n8n 的主机位置:

部署方式攻击者可访问的目标危害级别
单机部署本机回环地址、同网段内网服务中
容器部署容器网络内的兄弟服务、宿主机网关高
云服务器部署云厂商元数据接口、内部 API严重

修复和预防

  • 对用户可控的 URL 输入做严格校验。协议限制为 http/https,域名做白名单匹配,禁止 IP 字面量和内网网段。
  • n8n 本身不做 URL 拦截,所以要在前面加一层代理或防火墙规则,从网络层阻断对私网地址的出站请求。
  • 如果工作流处理的是外部用户提交的数据,尽量避免把完整 URL 交给用户拼接。用预设的下拉选项来限定请求目标。

2.3 任意 JavaScript 代码执行

漏洞原理

n8n 的 Code 节点支持用户直接写 JavaScript 代码,甚至还有 Execute Command 节点可以直接执行系统命令。在默认设计里,这属于平台功能,但风险在于:能够访问 n8n 后台的人可能不是你信任的人。

攻击场景

攻击者进入后台后,不用去猜你的系统口令,直接建一个 Code 节点,写一段脚本读取环境变量文件,或者把工作流里所有节点的配置都回传到自己的服务器。如果 n8n 运行在 Docker 容器中,攻击者还能尝试容器逃逸、挂载宿主机目录读取敏感文件。

影响范围

这属于高权限操作,一旦执行成功,等同于在运行 n8n 的主机上获得了一个 shell。后续如何提权、如何横向,取决于主机本身的加固程度。

修复和预防

  • 严格控制 n8n 后台的访问人员范围,这是最核心的一步。
  • 不要把 n8n 的容器以 root 用户运行,设置只读文件系统和独立用户。
  • 在 Docker 配置里禁用 Code 节点用不到的底层能力,比如通过受限 seccomp 配置、禁用宿主机目录挂载等方式降低逃逸风险。
  • 考虑对工作流的修改做审批机制,避免有人悄悄加入恶意节点。

2.4 敏感信息泄露:凭证存储与日志

漏洞原理

n8n 会把所有集成的凭证加密后存储在数据库中,加密密钥由环境变量N8N_ENCRYPTION_KEY控制。如果密钥泄露,数据库里的密文可以直接还原成明文。另外,工作流节点配置里经常包含各种 Key 和 URL,n8n 支持把执行数据保存到数据库,方便调试,但这些数据也可能包含敏感字段。

泄露路径

  • 环境变量被导出,攻击者拿到加密密钥和数据库备份。
  • 工作流执行日志里打印了完整的请求头或响应体,被低权限账号看到。
  • 凭证数据在导出/导入工作流时以明文 JSON 方式传递。

修复和预防

  • 加密密钥必须妥善保管,不要写进代码仓库或 docker-compose 文件里。建议用密钥管理服务托管。
  • 将数据库连接信息和 n8n 配置分离,数据库本身做独立访问控制,避免数据泄露面扩大。
  • 关闭不必要的执行数据保存,或者设置过期自动清理策略。
  • 导出工作流模板时,检查是否包含敏感字段,在分享到社区前清洗掉真实凭据。

3. 纵深防御落地:从部署到运行的一整套方案

3.1 网络层隔离:别把实例裸奔在公网

说了这么多漏洞,实操上最迫切的一件事就是别让 n8n 直接暴露在公网。一个很常见又很合理的场景是:我们确实需要 n8n 的 Webhook 功能接收外部平台的回调。但 Webhook 入口和后台管理入口是可以分开处理的。

我的建议是这样的网络结构:

  • 管理端(UI 界面)只允许通过内网访问,或者通过跳板机访问。
  • Webhook 端点单独用反向代理暴露,并且限定只转发到 n8n 的 Webhook 路由。
  • 所有的入站流量先经过一层 Web 应用防火墙,做基本的行为识别和 IP 封禁。

一个最小可用的 Nginx 反向代理配置长这样:

server { listen 443 ssl; server_name your-domain.example.com; # 管理端:加一层额外认证 location / { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/htpasswd; proxy_pass http://127.0.0.1:5678; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # Webhook 专用入口,限制只能访问 webhook 路径 location ~ ^/webhook/ { proxy_pass http://127.0.0.1:5678; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

这样做的好处是,就算 n8n 自身的某个认证逻辑出了漏洞,攻击者也需要先过掉 Nginx 这一层,给自己争取了缓冲时间。

3.2 容器运行时加固:给你的自动化引擎上把锁

用 Docker 部署 n8n 是主流方式,但默认的 docker run 配置其实有不少隐患。我把自己在用的安全基线配置整理出来参考:

version: "3.8" services: n8n: image: n8nio/n8n restart: unless-stopped user: "1000:1000" read_only: true tmpfs: - /tmp - /home/node/.n8n environment: - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY} - N8N_SECURE_COOKIE=true - N8N_PROXY_HOPS=1 volumes: - n8n_data:/home/node/.n8n networks: - internal_net security_opt: - no-new-privileges:true cap_drop: - ALL cap_add: - CHOWN - SETGID - SETUID logging: driver: "json-file" options: max-size: "10m" max-file: "3"

几个关键点的理由说一下:

  • read_only: true配合tmpfs,让容器文件系统不可写,攻击者想在容器里落地工具就得先绕过这一层。
  • 丢弃所有 Linux 能力,只保留最基本必要的三项,即使命令执行被攻破,也无法直接加载内核模块或修改系统配置。
  • 独立网络,避免和别的容器混在同一个 bridge 网络里,降低内部横向移动的概率。
  • 日志限制大小,防止日志被塞满磁盘导致 DoS。

3.3 数据与凭据保护:核心中的核心

n8n 的数据库和加密密钥属于等保里的"关键资产",优先保护它们准没错。我身边不少人把 n8n 和数据库装在同一个容器里,一旦容器被攻破,所有加密的凭证和数据库一并泄露。合理做法是分开部署,并且单独控制数据库的访问来源。

关于加密密钥,我有几个实操建议:

  • 不要把密钥写到镜像的环境变量里,用专门的密钥管理工具(比如云上密钥管理服务)或者 Docker Secret 来管理。
  • 定期轮换密钥。轮换时要考虑旧数据能否解密,先做好备份再操作。
  • 开启 n8n 的审计日志,记录谁在什么时间创建或修改了工作流、导出了哪些数据。出了事能快速定位责任人。

凭证库的访问控制也很重要。n8n 支持设置只读凭证,避免误改误删;从工作流模板市场导入现成模板时,一定要检查是不是包含额外的节点或异常请求地址。

3.4 工作流本身的代码审计要点

n8n 的工作流本质上是一段有状态的代码配置,它也会引入供应链风险。导入别人分享的工作流模板时,至少要看几个地方:

  • 是否有隐藏的 Code 节点或 Execute Command 节点。
  • HTTP 节点的请求地址是否指向不明第三方。
  • 是否有奇怪的 JSON 解析逻辑,试图从数据里提取条件值(这可能是在做动态拼接攻击)。
  • 节点之间的数据传递是否会把敏感字段发给非预期地址。

给团队定一条规矩:生产环境的所有工作流变更,必须经过安全审查,至少要有一个人在 Merge 之前检查过节点的完整截图或者导出 JSON。

4. 实操过程与核心环节实现:从零加固一台 n8n 服务器

4.1 加固检查清单

我梳理了一条快速自查路径,照着走一遍基本能覆盖 80% 的高危隐患:

  1. 确认 n8n 没有直接暴露 5678 端口,端口映射做了访问限制。
  2. 确认管理后台开启了登录保护,并且没有开放注册链接。
  3. 检查环境变量里是否有完整的加密密钥、数据库密码,如果有,更换并妥善保管。
  4. 确认容器是普通用户运行,文件系统只读,没有挂载宿主机的敏感目录。
  5. 检查工作流里 HTTP 节点的 URL 是否支持用户输入,如果支持,评估会不会被打到内网或云元数据。
  6. 检查数据库访问白名单,只允许 n8n 服务所在的 IP 访问。
  7. 确认日志留存策略,确保保留了至少 30 天的操作记录。

4.2 一步步操作:带认证的反向代理部署

假设你现在已经在一台服务器上跑起来了 n8n,我们来逐步把认证和反向代理补上。

第一步,生成一个强密码的 htpasswd 文件:

openssl passwd -apr1

输入你想设置的密码,把生成的结果存到 /etc/nginx/htpasswd 里。

第二步,创建 Nginx 配置文件,把上面的方案补全,加上 SSL 证书配置,并限定只允许特定 IP 访问后台:

server { listen 443 ssl; server_name your-domain.example.com; ssl_certificate /etc/letsencrypt/live/your-domain.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.example.com/privkey.pem; # 后台管理:加 IP 白名单 + 基础认证 location / { allow 192.168.1.0/24; deny all; auth_basic "Restricted Area"; auth_basic_user_file /etc/nginx/htpasswd; proxy_pass http://127.0.0.1:5678; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # Webhook 分发: location ~ ^/(webhook|webhook-test)/ { proxy_pass http://127.0.0.1:5678; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

第三步,重启 Nginx 并验证:

nginx -t systemctl reload nginx

这一步完成后,外部用户只能访问 Webhook 路径,后台界面需要额外的凭据和来源 IP 双重验证。

第四步,在 n8n 的环境变量里强制开启安全 Cookie,防止跨站脚本借道窃取登录会话:

N8N_SECURE_COOKIE=true N8N_PROXY_HOPS=1

配置完重启 n8n 容器,打开浏览器确认登录、工作流测试一遍正常,加固就算基本完成。

4.3 用防火墙做最终兜底

即使 Nginx 配好了,我仍然建议操作系统层面做一层防火墙兜底。以 iptables 为例,只保留必要的入站端口:

iptables -A INPUT -p tcp --dport 443 -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT -s 你的管理网段 iptables -A INPUT -p tcp --dport 5678 -j DROP

这里把 5678 直接丢弃,外部流量无法绕过 443 端口进入 n8n。用云服务器的话,就在安全组里做同样的配置,双重保险总没错。

5. 常见问题与排查技巧实录

5.1 认证配置了但还是能直接访问后台

这个坑我踩过。配置了 Nginx 的 auth_basic,打开页面仍然能直接进后台。后来排查发现,n8n 自己开了基于 Cookie 的会话,而 Nginx 只是挡了一层基础认证,没有真正阻断绕过。解决方案是:除了 Nginx 层认证,在 n8n 的环境变量里也开启基础认证,两个认证叠加。这样即使 Nginx 配置被规避,n8n 自身也能拦一道。

5.2 Webhook 测试正常但生产回调失败

有时候 Webhook 在测试模式下正常,但生产环境回调总是 404。原因是 n8n 的 Webhook 有两种模式,测试模式的路径后缀是 webhook-test,生产则是 webhook。如果你在 Nginx 只放行了带有 -test 的路径,生产回调自然进不来。反过来,如果只放行生产路径,开发调试时就会卡住。我的做法是两层都放行,但给 webhook-test 路径加一个内网 IP 白名单,避免外部测试流量乱入。

5.3 容器重启后工作流全部消失

容器重启或更新后,发现自建的工作流全部不见了。很多时候是因为数据卷没有正确挂载。docker-compose 里 volumes 配置指向了错误的路径,或者用了 Docker 默认匿名卷,导致数据没有持久化。记住 n8n 的数据目录是 /home/node/.n8n,挂载宿主机目录之前先确认路径写对。同时定期备份数据库文件,防止误操作导致数据丢失。

5.4 日志里出现来自陌生 IP 的扫描行为

如果你发现 n8n 实例的访问日志里有大量来自陌生 IP 的探测请求,说明实例已经被公网扫描器盯上了。第一反应应该是检查端口暴露范围,而不是盲目封 IP。只要 5678 端口对公网闭合,后台管理路径又有白名单,这些扫描请求就只是一堆噪音。实在不放心,可以在防火墙层面做地区级封禁或暴力破解保护限制。

5.5 凭证显示解密失败

某次重启 n8n 之后,所有工作流的凭证都提示解密失败。排查后发现是环境变量里的加密密钥变了,可能是部署配置更新时覆盖了原来的值,或者不同环境用了不同的密钥文件。n8n 的凭证加密和解密都依赖同一个密钥,一旦密钥对不上,历史凭证全部失效。解决办法是:把密钥当作核心资产来管理,变更环境时同步迁移密钥,且要先备份旧密钥。

6. 写在最后的几句实在话

这一套做下来,n8n 的安全性大幅提升。我见过太多团队栽在同一个问题上:能用就行,先把功能跑起来,安全后面再说。但这类自动化平台有个特点,它不是为了某一个业务存在的,而是连接所有业务的,数据流转得越快,安全要求越高。

我在实际运维中的体会是,n8n 本身的功能和安全边界其实很清晰,它把执行能力全都给你了,怎么用、用在哪,完全是运维者自己的决定。所以与其到处搜补丁,不如先把暴露面收住,再逐步加固。网络隔离是最便宜也最有效的一招,建议最先做;加密密钥和数据库保护其次,这两处一旦出事就是数据安全事故。

最后再分享一个小技巧:把 n8n 的版本升级和依赖更新纳入固定的例行维护,新版本通常会修复已知漏洞。升级之前先在测试环境跑一遍工作流,确认没有兼容问题再动生产。安全是一项持续工作,每多一道防线,攻击者就需要多花一分力气,而大部分攻击者会优先转向更容易的目标。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进