安全指南

安全运维 Next.js:建立不在已公开CVE上掉队的机制

对 Next.js 来说,最大的风险是放任已公开的 CVE 不修。现实中确实发生过把 CVSS 10.0 的 RCE 放任数月而被攻破的事故。本文结合本站的实际运维,讲解四项做法:以实际运行的版本判定、自动监控依赖、尽快更新、以最小权限运行。

发布于 2026-06-07 更新于 2026-10-06 4 分钟阅读
本页目录

对象:用 Next.js(或类似的 JS 框架)做应用并公开上线的人,尤其是「靠 AI 帮忙做出来、运维凭感觉」的人。这是从真实事故(→ 放任CVSS 10.0的经历)中提炼出来的内容。

本站的看法:重要的不是速度,而是不漏看的机制

个人开发者在安全上出问题,大多并非知识不足,而是因为无法让运维持续下去。比谁都早读到 CVE 速报并没有价值(速度交给厂商和新闻即可)。真正有效的是让与自己相关的 CVE 不被漏看的机制。所以本文重点不在多掌握知识,而在建立这种机制。

1. 以实际运行的版本判定

「是否在用危险的版本」,要用实际运行的版本来衡量,而不是清单里的下限。因为清单里的数字与实际运行的版本常常对不上。

✗ 按 package.json 的下限计数

"next": "^16.0.0" → 误判为「16.0.0 脆弱,所以我们也脆弱」,被过度统计为 「8个脆弱」。

✓ 按实际运行的版本计数

用 npm ls next 确认实际解析出的版本 → 已自动升级的是安全的,只有固定锁定的落后了。实际是2个。

package.json 的下限可能与实际运行的版本不同。以实际运行的版本来看,风险判断会改变(「8个脆弱」实际是2个)。
# see the versions actually resolved
npm ls next react react-dom
# inside a running container
docker exec <container> npm ls next

脱字符范围(^16.0.0)会在重新构建时自动升级,固定锁定的依赖则会落后。请以这里显示的版本来判定。

如何检查自己的环境

下面的步骤可以确认应用实际运行的是哪个版本,以及已知 CVE 是否适用。每一步都只检查你自己的环境。

1

确认本地版本

在项目文件夹里运行 npx next info。它会显示 next、react、react-dom 的实际版本,以及与最新版相差多少。npx next -v 只输出 Next.js 的版本。

2

查看为什么是这个版本

npm ls next(或 pnpm why next)会显示安装了哪个版本、经由哪个包引入。如果锁定文件(package-lock.json 或 pnpm-lock.yaml)没有提交,每次构建版本都可能变化,所以先把它提交。

3

确认生产环境运行的版本

在本地更新,不会改变仍在运行旧镜像的服务器。如果是容器,读取运行中的容器里 next 的 package.json 的 version 字段(命令见下)。使用 output: 'standalone' 时同样有效。

4

与已知 CVE 对照

npm audit --omit=dev 只检查会进入生产环境的依赖。加上 --audit-level=high 后,发现 High 及以上时会以非零状态退出,CI 可以据此中止。用 osv-scanner 扫描锁定文件也能达到同样目的。

5

阅读适用于自己环境的官方公告

Next.js 的公告有时会按 App Router 与 Pages Router、或自托管与托管服务区分影响范围。把公告中列出的修复版本与第 1 到 3 步查到的版本进行比较。

# local: actual versions and distance from latest
npx next info
# the version running inside the production container
docker exec <container> node -p "require('next/package.json').version"
# check only production dependencies; fail on High or above
npm audit --omit=dev --audit-level=high

运行方式不同,影响也不同

同一个 CVE,是否影响你取决于 Next.js 的运行方式。下面按部署方式整理两个过去的案例:

运行方式中间件授权绕过(CVE-2025-29927)RSC RCE(CVE-2025-55182)由谁更新
托管服务(Vercel、Netlify 等)不受影响(路由在另一个系统中运行)使用 App Router 则受影响;有拦截规则,但仍必须更新你自己(锁定文件决定下一个版本)
自托管(next start / standalone,含 Docker)受影响使用 App Router 则受影响你自己(重新构建镜像并重启)
静态导出(output: 'export')不受影响(没有运行中的服务器)没有接收请求的服务器,一般不会波及你自己(构建时的依赖仍需更新)

所以即使使用托管服务,提升 Next.js 版本也是你自己的工作。把平台的防护当作在升级到修复版之前争取时间的手段。

也要确认支持期限。按官方支持政策,截至 2026 年 10 月:

版本线状态(2026 年 10 月)安全修复
16.xActive LTS(新功能、修复、安全补丁)有
15.xMaintenance LTS(首次发布起两年)仅限重大问题
14.x 及更早不再支持严重问题时偶尔提供,没有保证

2. 自动监控依赖

靠人工追踪 CVE 坚持不下来,而那次遗漏就会变成事故。用工具自动监控。

免费的依赖监控

osv-scanner scan -L pnpm-lock.yaml

如果用 GitHub,就启用 Dependabot(仓库的 Settings → Advanced Security → Dependabot alerts)。只有与你的依赖相关的 CVE 才会以 PR 形式送来。

关键在于优先级。本站的立场是:按「是否正在被利用(KEV)」乘以「CVSS 有多高」来排序。CVSS 再高,如果你没用到,影响就小;分数中等但正在被利用,则要最优先。这种优先级判断是工作的核心。

3. 更新:升级到修复版,而不是临时规避

出现漏洞时,把框架升级到修复版,修复漏洞本身。

表面处置(不充分)

  • 只在反向代理上挡掉看起来像攻击的请求
  • 停掉扣费或症状就当作「已处置」
  • RCE 漏洞本身仍然留着

根本修复(正确)

  • 把框架升级到修复版
  • 升级后,在日志中确认攻击特征已经消失
  • 把止住损害与修复根本原因当作两项独立工作,两项都做

常见的失败

「停掉了扣费或症状」≠「已处置」。止住损害和修复漏洞是两项不同的工作,两项都要做。

真实案例:2025 年 12 月的 React Server Components 漏洞

下面以 2025 年 12 月公开的 React Server Components(RSC)漏洞为例,说明处理一个已公开的 CVE 实际是什么样子。以下内容全部来自 React 和 Next.js 的官方公告以及 CISA 的公开数据。

  1. 2025 年 12 月 3 日

    React 公开了 CVE-2025-55182(CVSS 10.0),无需认证即可在服务器上执行代码。在 Next.js 中,15.x、16.x 和部分 canary 版本上的 App Router 应用受影响(CVE-2025-66478);Pages Router 和 Edge Runtime 不受影响。没有临时规避办法,必须升级到修复版本(15.0.5、15.1.9、15.2.6、15.3.6、15.4.8、15.5.7、16.0.7 等)。
  2. 2025 年 12 月 5 日

    CISA 将其加入已确认遭到实际利用的漏洞目录(KEV)。
  3. 2025 年 12 月 6 日

    Next.js 补充说明:截至太平洋时间 12 月 4 日下午 1 点仍在线且未修补的应用,应更换所使用的机密(API 密钥等)。
  4. 2025 年 12 月 11 日

    在分析补丁的过程中,同一机制里又发现并修复了两个问题(拒绝服务和源代码泄露)。之后拒绝服务的修复被证明不完整,发布了 CVE-2025-67779,已升级的用户被要求再次升级。

由此可以得出三点运维上的教训:

  • 一次更新并不是终点。同一代码的后续修复可能隔几天就来
  • 平台的拦截规则只是补充,升级被明确为唯一完整的修复
  • 如果在修补前处于在线状态,除了更新之外还要更换机密

本站的看法:完成的标准是生产版本已修复,而不是执行过更新

像这次一样后续修复接连发布时,「上周已经升级过」就不再可靠。判断是否完成,要看生产环境运行的版本是否达到最新公告中的修复版本,而不是凭对工作的记忆。本站也是在确认容器已重新创建、并检查其中运行的版本之后,才把更新标记为完成。

常见错误及修正方法

  • 以 package.json 里的数字判断:安装的版本可能不同。用 npx next info 或 npm ls next 确认。
  • 更新锁定文件后就停下:在生产镜像重新构建并重启之前,旧版本会继续运行。确认生产环境里的版本。
  • 更新一次就觉得安全了:可能还会有后续公告。保持 Dependabot 等告警开启,并在几天内持续关注公告。
  • 交给平台的拦截规则:它们未必能挡住攻击的所有形式。要升级。
  • 继续使用不再支持的版本线:14.x 及更早版本的修复没有保证。规划迁移到 16.x。
  • 在只用于开发的依赖的噪声中漏看与生产相关的警告:先运行 npm audit --omit=dev 查看会进入生产的部分。
  • 忽视修补之前的那段时间:机密可能在那段时间被取走。更换 API 密钥和数据库密码(→ .env 与 API 密钥基础)。

4. 用最小权限限制损害

设计成即使应用被利用,损害也只限于局部。

1

以非特权用户运行

不要以 root 作为容器的 USER。这样即使被攻破,影响也只限于该用户被允许做的事。
2

DB/Redis 只绑定到内部网络

绝不对外公开。减少能被直接访问的范围。
3

按服务隔离

按服务拆分网络和数据,使一处被攻破不会扩散到全部。

这些决定了被攻破时是止于「窃取容器内的 env」,还是发展到「整台主机被接管」。

本站自己也这样做

本站正是按本文所写的方式,对自己的依赖进行 CVE 监控,不再把引发这一切的那种遗漏(放任已公开的 CVSS 10.0)交给人的注意力。我们说「按优先级(KEV+CVSS)排序」,是因为我们自己就是这样运维的。

延伸阅读

参考资料

  • Next.js「Security Advisory: CVE-2025-66478」(2025 年 12 月 3 日,12 月 6 日更新):nextjs.org
  • Next.js「Security Update: December 11, 2025」(CVE-2025-55183 / 55184 / 67779):nextjs.org
  • NVD「CVE-2025-55182」:nvd.nist.gov / CISA「Known Exploited Vulnerabilities Catalog」:cisa.gov
  • Vercel「React2Shell Security Bulletin」:vercel.com
  • Vercel「Postmortem on Next.js Middleware bypass」(CVE-2025-29927):vercel.com
  • Next.js「Support Policy」:nextjs.org / 「next CLI」:nextjs.org / 「Static Exports」:nextjs.org
  • npm Docs「npm audit」:docs.npmjs.com / OSV-Scanner「Usage」:google.github.io / GitHub Docs「Configuring Dependabot alerts」:docs.github.com

FAQ

QNext.js 的安全里最重要的是什么?
A

比起自己不写出 bug,更重要的是不要放任框架本体或依赖中已公开的 CVE 不修。大多数严重事故并非来自新型攻击,而是来自被放任的已知漏洞。

Q看 package.json 就能判断是否脆弱吗?
A

不能。package.json 里的 `^`(下限)不代表实际情况:脱字符范围会在重新构建时自动升级,固定锁定的依赖则会落后。请务必以实际运行的版本来判定。

Q个人开发该最先做的一件事是?
A

启用 Dependabot(GitHub)或 osv-scanner,自动监控依赖的 CVE。人工检查一定会有遗漏。能持续运转的机制比多掌握知识更有价值。

Q怎样确认自己正在运行的 Next.js 版本?
A

在项目文件夹里运行 `npx next info`,它会显示 next、react、react-dom 的实际版本。生产环境则要读取运行中的容器或服务器里 next 的 package.json 中的版本(正文第 3 步)。本地和生产环境不一定一致,两边都要确认。

Q托管在 Vercel 等平台上,也需要自己更新吗?
A

需要。2025 年 3 月的中间件授权绕过(CVE-2025-29927)不影响 Vercel 和 Netlify,但 2025 年 12 月的 React Server Components RCE(CVE-2025-55182)影响所有使用 App Router 的应用。Vercel 加入了自己的拦截规则(WAF),同时也表示无法挡住所有变种,必须升级到修复版本。

Q继续使用 Next.js 14 或更早的版本可以吗?
A

不推荐。按官方支持政策,14.x 及更早版本已不再支持;安全修复只会在严重问题时偶尔提供,且没有保证。截至 2026 年 10 月,受支持的是 16.x(Active LTS)和 15.x(Maintenance LTS)。维护期为首次发布起两年,所以如果在用 15.x,也要规划迁移到 16.x。