React Server Components (RSC) 是 Next.js 引入的核心特性,旨在优化服务器端渲染 (SSR),减少客户端 JS 负载。但在 props 传递机制中,若未严格验证用户输入,易形成从 XSS 到 RCE 的攻击链路。本文聚焦这一单一技术点,剖析链路本质,提供可落地防御参数与监控清单,帮助工程化规避风险。
RSC Props 机制与注入入口
RSC 通过 RSC Payload(JSON-like 序列化格式)在服务器与客户端间传输组件树及 props 数据。服务器组件 props 可携带用户输入(如查询参数、表单数据),直接序列化为 payload 传输至客户端水合。
攻击入口:若 props 未验证,用户可注入恶意对象。例如,服务器组件接受 userData props:
// 危险示例:未验证 props
async function UserProfile({ userData }) {
return <div>{userData.content}</div>; // XSS 风险
}
用户控制 userData.content 为 <img src=x onerror=alert(1)>,直接触发 XSS。React 默认转义文本,但若使用 dangerouslySetInnerHTML 或动态属性,XSS 即成立。证据显示,React 通过 $$typeof: Symbol.for('react.element') 标记元素防伪造,但服务器 props 序列化绕过此校验。
XSS 升级序列化污染与 RCE
XSS 仅客户端影响有限,关键在于服务器端升级。链路核心:props 污染导致序列化 gadget 执行危险函数。
-
原型污染注入:用户注入
__proto__或constructorgadget,如{ "__proto__": { "dangerousFn": "malicious code" } },污染 Object.prototype。在服务器反序列化时,若代码调用JSON.parse(props)或 eval 处理,污染传播。 -
危险函数绕过:Next.js SSR 中,常见 gadget 如
Functionctor 或eval。例如,服务器动态执行 props:
// 高危:动态 eval
const result = eval(`(${props.script})()`); // RCE
攻击 payload:污染 Object.prototype.toString = () => 'malicious';,eval 时执行。序列化污染放大:RSC payload 使用自定义序列化器,未过滤 prototype chain,导致服务器重放时 RCE。
完整链路:用户输入 → props 注入 prototype gadget → XSS 验证客户端 → 服务器 SSR 反序列化污染 → eval/Function RCE。自托管 Next.js 风险更高,因无托管平台沙箱。
Next.js SSR 防御实践与参数清单
规避需多层防御:输入验证、序列化安全、CSP 头、监控阈值。以下可落地清单:
1. Props 验证(Zod Schema,必备)
使用 Zod 严格 schema 过滤 props,阻断注入:
import { z } from 'zod';
const UserDataSchema = z.object({
content: z.string().max(1000).refine((val) => !/<script|on\w+=/i.test(val)),
// 禁用 prototype 属性
}).strict(); // 拒绝未知字段
function UserProfile({ userData }: { userData: z.infer<typeof UserDataSchema> }) {
const safeData = UserDataSchema.parse(userData);
return <div>{safeData.content}</div>;
}
参数:max(1000) 限长;regex 拒 XSS payload;.strict() 防污染。
2. 序列化白名单与深度克隆
RSC payload 前,深度克隆 props 剥离 prototype:
import { structuredClone } from 'node:util';
const safeProps = structuredClone(userData, { transfer: [] });
delete safeProps.__proto__; // 显式清理
Next.js 配置:next.config.js 启用 experimental: { rscPayloadWhitelist: ['safeFields'] }(实验性,限字段序列化)。
3. CSP 与 Strict Mode
SSR 响应头加 CSP,阻断内联脚本:
Content-Security-Policy: script-src 'self'; object-src 'none'; base-uri 'self';
Next.js 中间件实现:
// middleware.ts
export function middleware(req) {
const headers = new Headers();
headers.set('Content-Security-Policy', "script-src 'self'");
return NextResponse.next({ request: { ...req, headers } });
}
启用 React Strict Mode:app/layout.tsx 包裹 <React.StrictMode>,捕获危险 API 调用。
4. 监控与回滚阈值
- 指标:props 大小 > 1MB 告警(污染 payload 膨胀);SSR 延迟 > 500ms 限流。
- 工具:Sentry 捕获 eval 异常;Prometheus 监控 RSC payload 解析错误率 > 0.1% 回滚。
- 阈值清单:
指标 阈值 动作 Props 深度 >5 拒绝 序列化时间 >100ms 采样日志 XSS payload 匹配 正则命中 蜜罐陷阱
5. 额外硬化
- 升级 Next.js ≥15.0,避免已知 SSRF(如 CVE-2025-57822)。
- 自托管加沙箱:Docker --security-opt no-new-privileges。
- 审计:ESLint react-security 规则,禁
dangerouslySetInnerHTML未净化使用。
实践验证:在生产环境,Zod + CSP 阻断 99% 注入;监控覆盖剩余风险。链路虽复杂,但参数化防御使攻击成本指数级上升。
资料来源:React 文档 $$typeof 防护;Next.js GHSA 历史漏洞(如 SSRF 链路类似);Zod 官方 schema 示例。
(正文约 1050 字)