React2Shell攻击防护
背景
漏洞概述
2025 年 12 月 3 日,React Server Components 中一个严重的未认证远程代码执行(RCE)漏洞被公开披露,编号为 CVE-2025-55182(又名 “React2Shell”),CVSS v3.x 评分 10.0,CVSS v4 评分 9.3。
该漏洞允许未认证的攻击者通过发送单个 HTTP 请求,以运行 Web 服务器进程的用户权限执行任意代码。由于 React Server Components(RSC)被 Next.js 等主流框架广泛使用,暴露在互联网上的易受攻击系统数量巨大。
受影响的 RSC 包版本为 19.0、19.1.0、19.1.1 和 19.2.0:
react-server-dom-webpackreact-server-dom-parcelreact-server-dom-turbopack
已观测到的攻击活动
据 Google 威胁情报组(GTIG)报告,漏洞披露后迅速出现了大规模利用活动,涉及从机会型网络犯罪到国家级间谍组织的多个威胁集群:
| 威胁组织 | 部署的恶意软件 | 目标 |
|---|---|---|
| UNC6600(中国关联) | MINOCAT 隧道工具 | 全球 |
| UNC6586(疑似中国关联) | SNOWLIGHT 下载器 / VSHELL 后门 | 全球 |
| UNC6588(中国关联) | COMPOOD 后门 | 未知 |
| UNC6603(中国关联) | HISONIC 后门 | 亚太地区云基础设施 |
| UNC6595(中国关联) | ANGRYREBEL.LINUX | VPS 基础设施 |
| 经济利益驱动 | XMRIG 加密货币挖矿 | 广泛 |
此外,GTIG 还观察到伊朗关联的攻击者利用该漏洞。
我们观察到的攻击行为
Next.js Server Actions 通过 Next-Action HTTP 请求头来标识要调用的服务端函数。该请求头的值是构建时生成的 40 位十六进制哈希(如 a1b2c3d4e5f6...)。
攻击者利用这一机制,发送携带极短或任意 Next-Action 值的 POST 请求(如 "x"、"r"、"dontcare")来探测服务器。这会触发如下错误:
Failed to find Server Action "x". This request might be from an older or newer deployment.
这类探测请求会造成以下影响:
- 产生大量服务端错误日志
- 消耗服务器资源处理无效请求
- 作为进一步攻击的侦察手段(侦察成功后可能部署后门、挖矿程序等)
- 与 CVE-2025-55182(React2Shell)直接相关
修复建议
- 立即升级 React Server Components 至 19.0.1、19.1.2 或 19.2.1 以上(推荐升级至 19.2.3 以同时修复后续的 CVE-2025-55183、CVE-2025-55184、CVE-2025-67779)
- 部署 WAF 规则作为升级前的临时缓解措施
- 审计依赖:检查项目中是否包含受影响的 RSC 包
- 监控网络流量:检查由 Web 服务器进程发起的 wget/cURL 出站连接
- 入侵排查:检查
$HOME/.systemd-utils等隐藏目录、异常 cron 任务、shell 配置文件(如.bashrc)中的恶意注入
参考来源:Google Threat Intelligence - Multiple Threat Actors Exploit React2Shell (CVE-2025-55182)
请求特征对比
合法的 Server Action 请求:
POST / HTTP/2
Content-Type: text/x-component
Next-Action: 9a3b7c8d2e1f0a4b5c6d7e8f9a0b1c2d3e4f5a6b
恶意探测请求:
POST / HTTP/2
Content-Type: text/x-component
Next-Action: x
核心区别在于 Next-Action 值的长度和格式。合法值始终是 40 位十六进制字符串。
通用解决方案
拦截 Next-Action 请求头存在但值长度小于 20 个字符的 POST 请求。这个阈值是安全的,因为:
- 合法的 action ID 是 40 位十六进制哈希
- 20 字符远低于合法长度
- 仅在请求头存在时触发,不影响普通 POST 请求(表单提交、API 调用等)
各层防护方案对比
| 层级 | 方案 | 优点 | 缺点 |
|---|---|---|---|
| CDN/WAF | 基于请求头长度的防火墙规则 | 在边缘拦截,不消耗源站资源 | 可能需要付费功能 |
| 边缘计算 | 程序化检查请求头 | 灵活,免费套餐可用 | 配置稍复杂 |
| 应用层 | 中间件校验 | 无外部依赖 | 浪费服务器资源 |
| 反向代理 | Nginx/Caddy 请求头过滤 | 完全可控 | 需要自建基础设施 |
Nginx 示例
location / {
if ($request_method = POST) {
set $block_action "";
}
if ($http_next_action ~ "^.{1,19}$") {
set $block_action "${block_action}_short";
}
if ($block_action = "_short") {
return 403;
}
proxy_pass http://upstream;
}
Next.js 应用中间件示例
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
if (request.method === 'POST') {
const nextAction = request.headers.get('next-action');
if (nextAction && nextAction.length < 20) {
return new NextResponse('Forbidden', { status: 403 });
}
}
return NextResponse.next();
}
Cloudflare 解决方案
方案一:WAF 自定义规则(推荐)
路径: Cloudflare Dashboard → Security → WAF → Custom Rules
使用 matches 正则(需要 Business/Enterprise 套餐)
(http.request.method eq "POST" and any(http.request.headers["next-action"][*] matches "^.{0,19}$"))
使用 len() 函数(需要 Business/Enterprise 套餐)
(http.request.method eq "POST" and any(len(http.request.headers["next-action"][*]) < 20))
严格格式校验(需要 Business/Enterprise 套餐)
仅允许合法的 40 位十六进制哈希通过:
(http.request.method eq "POST" and any(http.request.headers["next-action"][*] ne "") and not any(http.request.headers["next-action"][*] matches "^[a-f0-9]{40}$"))
Free/Pro 套餐替代方案
matches 和 len() 运算符需要 Business 套餐。Free/Pro 套餐可以使用 or 枚举已知的攻击值:
(any(http.request.headers["next-action"][*] eq "x")) or
(any(http.request.headers["next-action"][*] eq "dontcare")) or
(any(http.request.headers["next-action"][*] eq "r"))
注意: 此方案只能拦截已知的攻击模式。需要持续观察日志,发现新的攻击 payload 后手动添加。
操作建议: 先将 Action 设为 Log 观察,确认无误杀后再切换为 Block。
方案二:Cloudflare Workers(所有套餐可用)
对于 Free/Pro 套餐需要通用长度检查的场景,可以使用 Workers 在边缘执行:
export default {
async fetch(request, env) {
const action = request.headers.get('Next-Action');
if (request.method === 'POST' && action && action.length < 20) {
return new Response('Forbidden', { status: 403 });
}
return fetch(request);
}
};
Workers 在边缘运行,无套餐限制,提供与 WAF 正则规则相同的防护效果。
注意事项
- Cloudflare 在 WAF 表达式中会将所有请求头名称转为小写。始终使用
next-action,而非Next-Action。 - 规则仅在
Next-Action请求头存在时触发,不影响正常的 POST 流量。 - 部署后在 Security → Events 中监控规则命中情况,确认拦截效果且无误杀。