news 2026/2/24 9:41:01

React 背锅了?一行恶意 JSON 就能让你的 Node.js 服务器瞬间宕机!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
React 背锅了?一行恶意 JSON 就能让你的 Node.js 服务器瞬间宕机!

近期,Node.js 官方发布了一系列重要的安全更新,修复了 8 个安全漏洞。这次更新涉及 Node.js 20.x、22.x、24.x 和 25.x 等所有活跃版本,影响范围之广,几乎覆盖了所有使用 React Server Components、Next.js 或 APM 监控工具的生产环境应用。

问题到底出在哪里?

在 Node.js 的异步编程世界里,有一个叫async_hooks的底层 API。它的作用是追踪异步操作的生命周期。听起来很技术化,但你可能每天都在用它,只是不知道而已。

React Server Components 用它来追踪渲染上下文,Next.js 用它来追踪请求信息,Datadog、New Relic 等 APM 工具用它来追踪请求链路。可以说,async_hooks已经成为现代 Node.js 应用的基础设施。

但问题就出在这里。当你的代码出现深层递归,导致栈溢出时,正常情况下 Node.js 会抛出一个RangeError: Maximum call stack size exceeded错误,你的try-catch可以捕获它,你的错误处理器可以记录它,然后应用继续运行。

但如果启用了async_hooks,情况就完全不同了。当栈溢出发生时,Node.js 会直接以退出代码 7 终止进程,不经过try-catch,不触发uncaughtException处理器,就这样,应用死了。

为什么这么容易被触发?

需要明确的是,这个 BUG 的触发需要满足几个条件:

  1. 启用了async_hooks(使用 AsyncLocalStorage、APM 工具等)

  2. 代码中存在深度递归

  3. 递归过程中创建了 Promise(触发 async hooks)

  4. 递归深度达到栈溢出的程度

虽然听起来条件挺多,但在实际应用中,这些条件很容易同时满足。让我举个实际的例子。

假设你有一个 Next.js API 路由,用来处理用户上传的 JSON 数据:

export defaultasyncfunction handler(req, res) { try { const data = req.body; const result = processNestedData(data); res.json({ success: true, result }); } catch (err) { // 你以为这里能捕获错误?天真了 console.error('Processing failed:', err); res.status(500).json({ error: 'Processing failed' }); } } function processNestedData(data) { if (Array.isArray(data)) { return data.map(item => processNestedData(item)); } return transform(data); }

一切看起来都很安全,对吧?有try-catch,有错误处理。

但如果有人发送一个嵌套了几千层的 JSON 数组,你的服务器会直接崩溃。不是返回 500 错误,而是整个进程退出,所有正在处理的其他请求都会中断。

这就是一个典型的 DoS(拒绝服务)攻击向量。

技术原因是什么?

问题的根源在于async_hooks的实现方式。当你创建一个 Promise 时,V8 引擎会同步调用 promise hook,这个 hook 会触发 Node.js 的async_hooks回调。

这意味着,每次new Promise()都会在当前调用栈上添加额外的栈帧。当你的代码递归创建 Promise 时,栈上既有用户代码的帧,也有async_hooks的帧。

当栈最终溢出时,抛出错误的那一刻,执行上下文正好在async_hooks的回调里。Node.js 为了避免在 hook 内部出现错误导致的不一致状态,会用一个特殊的错误处理器TryCatchScope::kFatal来包裹这些回调。

kFatal的意思是:如果这里出错了,状态已经不可恢复,直接退出进程。

虽然这个设计的初衷是为了保护应用,但在栈溢出这个场景下,它反而成了问题。因为错误本身来自用户代码,而不是 hook 本身。

Node.js 是怎么修复的?

这次的修复方案很巧妙。Node.js 在TryCatchScope的析构函数里增加了一个检测:如果捕获到的是栈溢出错误,就把它重新抛给用户代码,而不是当作致命错误处理。

TryCatchScope::~TryCatchScope() { if (HasCaught() && mode_ == CatchMode::kFatal) { Local<Value> exception = Exception(); // 检测到栈溢出?重新抛出而不是退出 if (IsStackOverflowError(env_->isolate(), exception)) { ReThrow(); Reset(); return; } // 其他致命错误:按原逻辑退出 FatalException(/* ... */); } }

这样一来,栈溢出错误就能像正常情况下一样被try-catch捕获了。

为什么说这只是缓解措施?

Node.js 官方在博客中特别强调:这只是一个缓解措施(mitigation),而不是根本性的解决方案。

原因很简单:栈溢出的行为本身就不是 ECMAScript 规范的一部分。JavaScript 规范假设栈空间是无限的,没有规定引擎应该在栈溢出时做什么。

抛出可捕获的RangeError只是 V8 等引擎的「尽力而为」行为。依赖这种未定义的行为来保证服务可用性,本身就是有风险的。

正确的做法是:如果你的代码可能处理深度不确定的递归结构(比如用户上传的 JSON),应该主动限制递归深度,或者用迭代算法替代递归。

function processNestedData(data, maxDepth = 100) { function process(item, depth) { if (depth > maxDepth) { thrownewError('Nesting too deep'); } if (Array.isArray(item)) { return item.map(child => process(child, depth + 1)); } return transform(item); } return process(data, 0); }

不要指望运行时帮你兜底。

还有哪些漏洞被修复?

除了这个栈溢出问题(CVE-2025-59466),这次更新还修复了其他几个重要漏洞:

CVE-2025-55131(高危):Buffer 分配时的竞态条件可能导致未初始化的内存泄露,从而暴露敏感信息如 token、密码等。

CVE-2025-55130(高危):通过精心构造的符号链接路径可以绕过文件系统权限模型,读写任意文件。

CVE-2025-59465(高危):发送畸形的 HTTP/2 HEADERS 帧可以让服务器崩溃。

CVE-2026-21636(中危):权限模型可以被 Unix Domain Socket 绕过,访问本地特权服务。

CVE-2026-21637(中危):TLS PSK/ALPN 回调中的异常可能导致进程崩溃或文件描述符泄露。

CVE-2025-59464(中危):处理 TLS 客户端证书时的内存泄漏。

CVE-2025-55132(低危)fs.futimes()可以绕过只读权限修改文件时间戳。

这些漏洞涵盖了内存安全、权限模型、网络协议等多个层面,影响范围确实很广。

哪些版本受影响?

好消息是,Node.js 团队已经为所有活跃版本发布了补丁:

  • Node.js 25.3.0(当前版本)

  • Node.js 24.13.0(LTS)

  • Node.js 22.22.0(LTS)

  • Node.js 20.20.0(LTS)

如果你还在使用更老的版本(18.x 及以下),这些版本已经停止维护,不会收到安全补丁。如果无法升级,可以考虑联系 OpenJS 基金会的商业支持。

特别需要注意的是,如果你在使用 Node.js 24 或更新版本,React 和 Next.js 应用不会受到栈溢出问题的影响,因为AsyncLocalStorage在这些版本中已经用 V8 的新 APIAsyncContextFrame重新实现,不再依赖async_hooks

但是,如果你的 APM 工具直接使用了async_hooks.createHook(),所有版本仍然受影响。


如果你正在生产环境使用 Node.js,特别是:

  • 使用了 React Server Components

  • 使用了 Next.js

  • 使用了任何 APM 工具(Datadog、New Relic、Dynatrace、Elastic APM、OpenTelemetry 等)

  • 使用了AsyncLocalStorage

你应该尽快升级到上述的补丁版本。

同时,检查你的代码中是否有处理不可信输入的递归逻辑,加上深度限制或改用迭代算法。

写在最后

这次漏洞揭示了一个有趣的现象:我们每天依赖的基础设施,可能建立在一些未被明确保证的行为之上。

async_hooks从一个调试 API 发展成了整个生态系统的关键依赖。React、Next.js、所有主流 APM 工具,都在用它。但它的某些边界情况,却从未被充分测试和规范化。

这不是某个框架或工具的问题,而是整个生态系统演化过程中的自然结果。当一个 API 变得足够流行,它的每一个实现细节都可能成为事实标准。

好在 Node.js 团队及时发现并修复了这个问题。但更重要的是,这提醒我们:不要假设运行时会永远按照你期望的方式工作,特别是在处理边界情况时。

防御性编程,永远不过时。

一个有趣的社区讨论

这次漏洞披露后,在开发者社区引发了一些有趣的讨论。

有开发者在推特上评论说:"Next.js 真是被诅咒了,拜托别再试图重新发明 PHP 了,天哪"(next.js is cursed tbh, just stop trying to reinvent php please omg)。

Node.js 核心维护者 Matteo Collina 则直接指出:"核心问题出在 React。"(The "core" problem is in React.)

这个对话很有意思。很多人把矛头指向 Next.js,但技术上说,问题的根源确实在 React Server Components 对AsyncLocalStorage的使用。Next.js 只是在此基础上构建的框架。

这也提醒我们,在讨论技术问题时,准确定位问题的层次很重要。表面上看起来是某个框架的问题,实际上可能是更底层的设计决策带来的影响。

当然,这并不是说 React 或 Next.js 做错了什么。它们使用AsyncLocalStorage是合理的选择,只是碰上了 Node.js 实现中的一个边界情况。技术栈的复杂性就在于此:每一层都在合理地使用下一层的 API,但层与层之间的交互可能产生意想不到的问题。


参考资料:

  • Node.js 官方博客 - Mitigating Denial-of-Service Vulnerability

  • Node.js 2026 年 1 月安全发布公告

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/24 7:26:14

Qwen3-4B-Instruct企业级部署:高可用集群架构设计实战

Qwen3-4B-Instruct企业级部署&#xff1a;高可用集群架构设计实战 1. 为什么需要企业级集群部署——从单卡推理到生产就绪的跨越 你可能已经试过在一块4090D上跑通Qwen3-4B-Instruct&#xff1a;镜像拉起来&#xff0c;网页打开&#xff0c;输入“写一封客户感谢信”&#xf…

作者头像 李华
网站建设 2026/2/21 20:23:32

Sambert如何接入Web应用?Gradio集成实战教程

Sambert如何接入Web应用&#xff1f;Gradio集成实战教程 1. 为什么选Sambert语音合成——开箱即用的多情感中文体验 你有没有遇到过这样的场景&#xff1a;想快速给产品加一段中文语音播报&#xff0c;但试了几个TTS工具&#xff0c;不是发音生硬像机器人&#xff0c;就是配置…

作者头像 李华
网站建设 2026/2/20 23:18:40

新手必看!YOLOv10镜像安装与预测全解析

新手必看&#xff01;YOLOv10镜像安装与预测全解析 你是不是也遇到过这些情况&#xff1a;下载完YOLOv10代码&#xff0c;配环境配到怀疑人生&#xff1b;好不容易跑通了&#xff0c;一换图片就报错&#xff1b;想试试TensorRT加速&#xff0c;结果卡在ONNX导出那一步……别急…

作者头像 李华
网站建设 2026/2/17 22:19:27

Z-Image-Turbo本地运行卡?资源监控与性能调优教程

Z-Image-Turbo本地运行卡&#xff1f;资源监控与性能调优教程 Z-Image-Turbo是阿里巴巴通义实验室开源的高效AI图像生成模型&#xff0c;作为Z-Image的蒸馏版本&#xff0c;它以极快的生成速度&#xff08;仅需8步&#xff09;、照片级的真实感画质、出色的中英双语文字渲染能…

作者头像 李华
网站建设 2026/2/21 12:11:30

Qwen3-4B部署教程:基于Docker一键启动网页推理接口

Qwen3-4B部署教程&#xff1a;基于Docker一键启动网页推理接口 1. 什么是Qwen3-4B-Instruct-2507&#xff1f; 你可能已经听说过阿里最近开源的这款大模型——Qwen3-4B-Instruct-2507。它是通义千问系列中的一颗新星&#xff0c;专为高效推理和实际应用而优化。相比前代模型&…

作者头像 李华
网站建设 2026/2/17 22:13:04

Qwen All-in-One快速入门:Web界面接入详细步骤

Qwen All-in-One快速入门&#xff1a;Web界面接入详细步骤 1. 什么是Qwen All-in-One&#xff1f;——一个模型&#xff0c;两种能力 你有没有试过这样的场景&#xff1a;想快速判断一段文字的情绪倾向&#xff0c;又顺手想和AI聊两句&#xff1f;以前可能得打开两个工具、加…

作者头像 李华