博客 / CVE 解读

React2Shell 事件之后:每一次服务端组件审计都需要的三道安全边界

一套针对 React2Shell 和 CVE-2026-23864 的技术审计方法:把安全解码、权限检查和有界算力分开审查,再验证实际部署的构建版本。

已完成信息安全方向博士研究生学业已通过校内答辩 · 最终学位论文答辩尚待进行

代价高昂的错误:把一个补丁当作整次评估

React2Shell(CVE-2025-55182)于 2025 年 12 月 3 日被披露,是 React Server Components 中一个无需身份认证即可远程执行代码的漏洞。React 官方将发现者署名为 Lachlan Davidson。官方公告将该问题归类为不安全的反序列化。[1, 6]

对产品负责人来说,真正值得问的问题是:已部署的服务能否安全地把一个外部请求转化为服务器端的处理工作?本文提出一种三道边界的审计方法:允许的取值、允许的操作,以及允许消耗的资源。这是对相关公开资料的编辑性分析,资料核实于 2026 年 10 月 4 日,并不代表作者发现或复现了这些漏洞。

从实际部署出发判断暴露面,而不是看产品名称

请盘点 RSC 集成方式,以及实际解析到的 react-server-dom-webpack、react-server-dom-parcel 或 react-server-dom-turbopack 版本。没有服务端执行能力、也没有支持 RSC 集成的 React 应用,不在最初公告的范围之内。但没有显式编写 Server Function,本身并不能证明某个支持 RSC 的部署就不受影响。[1]

请记录生产镜像或部署标识符、依赖解析结果、框架配置以及可达的请求处理器。一份已打过补丁的开发者本地代码,并不能说明某个旧版本部署、预览环境或回滚镜像实际运行的是什么。请把“软件包存在”“存在易受攻击的版本”和“相关代码路径可达”这三件事分开来看——它们是三个不同的论断,各自都需要独立的证据支撑。

第一道边界:字节只能被转换为允许的取值

反序列化远不止检查一个请求是否看起来像 JSON 那么简单。解码器可能会重建引用、解释类型,或解析延迟求值的数据。审计要问的问题是:在应用程序完成校验之前,攻击者能够诱使服务器构造出哪些含义?请沿着真实的框架集成来追踪这一转换过程,而不要想当然地假设业务处理函数收到的都是无害的基本类型。

下面的模型只是审计辅助工具,既不是 React 的内部调用图,也不是一份利用手册。请明确哪些取值类型是可接受的、引用是如何处理的,以及错误路径有哪些。在隔离环境中,通过文档记录的入口点测试畸形和存在歧义的输入。一个被拒绝的小请求,不应该留下部分重建的状态,让另一个请求有机会复用它。这最后一条,是需要在您自己的产品中加以调查的不变量,而不是针对这些 CVE 的指控。

HTTP input
  -> [1] decode into permitted values
  -> [2] authorize the requested operation
  -> [3] execute within an explicit work budget
  -> produce a permitted response

Review invariants:
  malformed input -> bounded rejection
  unauthorized operation -> no state change
  excessive work -> bounded termination
  error response -> no sensitive implementation data

第二道边界:函数可被调用,不等于这次调用已获授权

React 关于 Server Functions 的文档说明了客户端调用是如何变成触发服务端代码执行的网络请求的。但这种传输能力本身,并不能提供您产品所需的对象级权限控制。[5] 对于一个会修改发票的函数来说,服务器必须确认调用者是谁、这张发票属于哪个租户,以及该主体是否被允许执行这一具体的状态变更。

请使用一个权限矩阵,分别测试匿名访客、正确租户的成员、其他租户的成员,以及一个只读账户。同时检查返回的响应和实际存储的状态。即便 HTTP 状态码看起来令人安心,如果拒绝请求的时候更新其实已经发生,那也是一次授权边界的失守。请对间接调用、批量操作以及应用实际接受的其他标识符重复进行这些检查。

第三道边界:合法的输入,依然可能要求不可接受的计算量

CVE-2026-23864 于 2026 年 1 月 26 日披露,涵盖了 RSC 中另外几种拒绝服务场景。维护者描述的后果包括 CPU 占用过高、内存耗尽以及进程崩溃。[3] React 明确表示,这些后续问题并没有重新打开 React2Shell 那个远程代码执行漏洞。请区分每个补丁各自解决的是哪方面的安全属性。[2]

请求体大小上限衡量的是传入的字节数,并不能直接限制这些字节所触发的计算量。在存在相应机制的地方,请审查引用展开、重复解析、下游调用以及取消执行的行为。请为产品选择符合实际的 CPU、内存、并发度和完成时限。超时机制只有在底层工作真正停止的情况下才有意义。请使用测试环境和预先设定好的中止阈值;故意耗尽一个生产环境进程并不是一次有价值的验收测试。

检查生产环境的响应内容,包括打包产物中实际包含了什么

CVE-2025-55183 涉及特定 Server Functions 配置下的源代码泄露问题。该公告将硬编码在被暴露源码中的密钥描述为存在风险;但它并没有确认这个具体漏洞会导致运行时环境变量值的普遍泄露。打包工具的内联处理,可能会影响生产产物中实际可见的源码内容。[4, 2]

请审查返回值、隐式的字符串转换、错误信息,以及编译后的函数体。在一个专用的测试构建中使用一个无害的标记值,检查实现细节是否会跨越响应边界被泄露出去。单个标记测试结果为阴性,只是有限的证据,并不能证明所有响应路径都是安全的。请把这项检查与 RCE 事件调查区分开来——在 RCE 场景中,一个已被攻陷的进程可能对密钥拥有远比这里广泛得多的访问权限。

建立一份开发人员可以复现的边界检查记录

下面这份记录表把路由和已部署的构建版本,与执行主体、输入类别、预期结果和观察到的证据关联起来,它是一份建议使用的报告模板。请用真实的测量数据填写它,而不是把一次理论上的攻击描述成已确认的发现。对于每一个被拒绝的操作,请记录状态确实没有发生变化;对于每一次资源测试,请记录工作是何时停止的、实际生效的是哪些限制。

2026 年 1 月的公告把 19.0.4、19.1.5 和 19.2.4 列为其涉及的 RSC 软件包的修复版本。这些只是历史上的补丁节点,并不是建议您把部署永远固定在这些版本上,也不代表此后不会再有新的公告。[3] 请选择当前仍受支持、已打过补丁的框架版本,重新构建并重新部署,然后在这个确切的产物上验证实际解析到的依赖包以及相关行为。

route_id | deployed_build | package_versions
principal | tenant | object | requested_operation
input_class | expected_result | observed_result
cpu_time | peak_memory | downstream_calls
state_before | state_after | reviewer | evidence_ref

一次有价值的评估应当为产品负责人提供什么

请要求对方给出一个明确的暴露面结论、支撑这一结论的依赖和部署方面的证据,以及关于解码、权限、资源使用和响应泄露这几方面各自独立的结论。每一项发现都应当说明其前提条件、受影响的业务流程、在约定环境中的复现过程、实际影响以及验证标准。一份罗列了许多 CVE 编号的亮眼清单,并不能替代这些结论与您自己应用之间的具体关联。

对于一次范围明确的审计,请选择一个高价值的业务流程,例如开票、账户管理或租户数据访问。把源码审查与约定好的行为测试结合起来,保留这份边界检查记录,并在修复后的部署上重新测试。在审查 Java 反序列化或原生解析器时,同样的“含义、权限和算力预算”三者分离的思路也同样有用,只是它们各自的机制和漏洞仍需独立调查。

参考来源

需要在您自己的产品中检查这个问题吗?

安全代码审计

想学会自己发现这类漏洞吗?

安全代码审计课程(一对一)
全部文章

08联系

即将上线处理用户数据的产品?

给我发一份简要需求。我会在三天内回复问题或方案大纲,价格在开始前以书面形式确定。