返回
2026/10/27
应对 Tailworm:在不影响生产的前提下加固我们的 Tailscale 网络
我们如何对照 Tailworm 的发现检查自己的 Tailscale 网络,移除 Tailscale SSH 暴露面,同时保持所有生产任务正常运行。
概述
2026 年 10 月 25 日,一位安全研究人员发布了“Tailworm”:针对 Tailscale 和 headscale 的 11 项发现,且未经协调披露(coordinated disclosure)。截至撰写本文时,Tailscale 尚未发布修复。当天晚上,我们就对照每一项发现检查了自己的 Tailscale 网络。我们移除了唯一一处与我们相关的暴露面,收紧了访问权限,期间所有生产任务始终正常运行。
本文介绍我们检查了什么、改变了什么、如何避免了故障,以及从中学到了什么。本文并非对该报告的独立验证。
Tailworm 报告内容简述
这 11 项发现大致可分为以下几类:
- Tailscale SSH(最严重)。经过授权的 SSH 会话可以提权为目标机器上的 root。在研究人员的实验环境中,攻击随后在机器之间扩散。
- App connectors。未对目标地址(destination)进行校验。
- 内存耗尽,发生在控制服务器和客户端中。
- Serve 和 Funnel 的边界情况。
每一项发现都要求攻击者事先已有立足点,没有一项是可直接从互联网发起的远程攻击。部分安全从业者认为报告的表述夸大了风险,但主要的暴露面 Tailscale SSH 是真实存在的,而且很容易移除。
第 1 步:先检查,再改动
我们从只读检查开始,并在改动任何东西之前记录了结果:
- 正在使用的 Tailscale 客户端版本
- 实际启用了哪些功能
- 60 天的 SSH 会话日志,查看谁从哪里连接,以及是否有人使用了端口或套接字转发
- 设备列表,包括数月未上线的设备
检查结果:
- 我们部分环境启用了 Tailscale SSH,因此发现 F1–F3 和 F5 与我们相关。
- 其他发现所依赖的功能我们并未使用,因此大多数不适用。
- SSH 日志中没有意外的来源,也没有转发请求。
第 2 步:在不造成故障的情况下移除暴露面
显而易见的做法是关闭 Tailscale SSH,改用标准的 OpenSSH 密钥认证。但我们的预检查发现了一个陷阱。
Tailscale SSH 依据 tailnet 身份进行认证,而不是 SSH 密钥。我们的自动化脚本在命令行中指定了一个 SSH 密钥,但该密钥受口令保护,根本不可能在无人值守的情况下工作。这些任务之所以能运行,只是因为 Tailscale SSH 从不检查密钥。如果我们直接关闭 Tailscale SSH,所有自动化任务都会停止。
因此,我们按以下顺序进行了切换:
- 创建了自动化专用密钥,仅允许来自一台源机器,并禁用转发。
- 在切换前测试了新路径。我们开放了一个仅在 tailnet 内可达的临时 OpenSSH 端口,并在与任务运行环境相同的条件下(无 SSH 代理、无终端),用脚本调用 SSH 的每一种方式进行连接。
- 进行了反向测试。确认新密钥在允许来源之外会被拒绝,转发请求也会被拒绝。
- 先设置好自动回滚。在关闭 Tailscale SSH 之前,我们安排了一个定时器,到时会自动重新启用它。这条恢复路径不依赖 SSH 是否可用。
- 切换后,用新连接逐一检查所有自动化任务。每个任务都实际完成了一次运行。我们没有把已经打开的会话当作证据。
- 移除临时配置——额外的端口、防火墙规则和回滚定时器——并再次验证。
第 3 步:收紧剩余部分
- 清空了 Tailscale SSH 策略。默认策略允许用户从自己的任何设备向自己的其他设备打开 SSH 会话(包括以 root 身份),只需每周在浏览器中重新批准一次。我们清空了该策略,因此即使误将 Tailscale SSH 重新启用,也不会再授予访问权限。
- 关闭了来自互联网的 SSH。关闭之前,我们确认了带外(out-of-band)控制台登录可用,以免把自己锁在外面。之后我们从外部网络验证 SSH 已不再响应。
- 启用了设备审批。新设备必须经管理员批准才能加入。
- 检查了注册密钥。没有需要吊销的密钥。
- 确认管理员账户已启用 MFA。任何接管了管理员登录的人都可以撤销网络层面的控制措施。
- 开始观察设备之间的真实流量,以便下一步——缩小哪些设备可以访问哪些服务——基于证据,而不是猜测。
Tailnet Lock 和设备审批都能防止恶意设备加入,但两者不能同时使用,请审慎地选择其一。
第 4 步:不仅修复服务器,也要修复运维手册
我们原来的恢复流程要求在启用 Tailscale SSH 的情况下重新连接服务器。如果在这次变更之后照此操作,就会在不知不觉中让这个有风险的功能重新回来。我们重写了流程:
- 先诊断。是网络连接中断了,还是 SSH 本身(密钥、配置、防火墙)出了问题?两者的修复方法不同。
- 重新连接时不改动设置。不添加额外参数,重新连接前保存节点设置,连接后进行对比。
- 紧急访问只在定时器控制下开放。先获得批准,开放前安排自动关闭,限制来源,并同时检查 IPv4 和 IPv6。
- 即使在紧急情况下也不重新启用 Tailscale SSH。它所需的访问策略变更无法自动回滚。
我们的收获
- 在移除一项安全功能之前,先弄清它实际认证的是什么。我们脚本中指定的密钥从未被使用过。
- 测试你要迁移到的那条路径本身,在任务实际运行的相同环境中,于切换之前完成测试。
- 设置一个不依赖于变更对象的回滚机制。用定时器,而不是“我们再 SSH 进去修就行”。
- 关门之前,先确认恢复用的访问途径。我们在关闭来自互联网的 SSH 之前确认了控制台访问。
- 在同一次变更中更新运维手册。一个过时的恢复步骤可能在几个月后撤销一项安全修复。
- 阅读默认策略。“允许自己的设备互相访问,包括 root”正是我们最初的默认设置。
- 把“变更成功”与“漏洞已解决”区分开来。我们已不再受 Tailscale SSH 相关发现的影响,但在上游修复发布之前,Tailworm 整体问题并未解决。修复发布后我们会更新客户端。
- 先测量,再收紧。先掌握观察到的流量和真实依赖关系清单,再制定更严格的访问规则,这样加固就不会影响业务。
下一步
我们正在根据观察到的流量,把设备之间的网络访问收窄到每项服务所需的最小范围。Tailscale 的修复一经发布,我们会立即安装。
参考资料:Tailworm 报告(tailworm.com)以及 Tailscale 关于 Tailnet Lock 的文档。
Global
Japan
Korea
Taiwan
Vietnam
Thailand
Indonesia
Portugal
Spain
France
Germany
Egypt
Russia