文章目录

React taintUniqueValue防止敏感数据传递到客户端

发布于 2026-05-02 18:19:08 · 浏览 4 次 · 评论 0 条

React taintUniqueValue防止敏感数据传递到客户端

在 React Server Components 和 Client Components 的交互过程中,服务器端的数据往往会自动序列化并传递给客户端。如果数据对象中混入了敏感信息(如 API 密钥、用户令牌、个人隐私等),这些信息可能会意外泄露到浏览器中。experimental_taintUniqueValue(或 taintUniqueValue)是 React 提供的一种防御机制,用于在运行时标记敏感数据,阻止其跨越服务器与客户端的边界。

以下指南将演示如何配置并使用此功能来锁定敏感数据。


1. 创建模拟的敏感数据源

首先,需要在服务器组件中准备一个包含敏感信息的对象。假设这是一个从数据库获取的用户对象,其中包含不应泄露的 authToken

定义 data 对象,使其同时包含公开信息(username)和敏感信息(secretKey)。

// app/server-action.ts
'use server';

import { experimental_taintUniqueValue } from 'react';

export async function getUserData() {
  // 模拟从数据库获取的数据
  const userData = {
    id: 'user_123',
    username: 'alice_dev',
    email: 'alice@example.com',
    // 这是一个敏感的 API 密钥,绝不能发送到客户端
    secretKey: 'sk_live_51MzQ...' 
  };

  return userData;
}

2. 标记敏感值为“污点”

使用 experimental_taintUniqueValue 对敏感字段进行标记。一旦标记,React 将会追踪这个特定的值。如果尝试将包含此值的对象传递给客户端组件,React 会抛出错误。

引入 experimental_taintUniqueValue 函数。

调用 该函数,传入原因、敏感值和错误提示信息。

// app/server-action.ts (修改 getUserData 函数)
export async function getUserData() {
  const userData = {
    id: 'user_123',
    username: 'alice_dev',
    email: 'alice@example.com',
    secretKey: 'sk_live_51MzQ...' 
  };

  // 标记 secretKey 为敏感数据
  experimental_taintUniqueValue(
    'Do not pass the secret API key to the client.', // 原因
    userData.secretKey,                              // 敏感值
    'SecretKey is leaked in getUserData',            // 调试信息
  );

  return userData;
}

3. 验证拦截效果(错误演示)

为了验证 taintUniqueValue 是否生效,尝试直接将包含 secretKeyuserData 对象传递给一个客户端组件。React 应该会检测到被污染的值并阻止渲染。

创建 一个客户端组件 ProfileClient,接收 user 数据。

// components/ProfileClient.tsx
'use client';

export default function ProfileClient({ user }: { user: any }) {
  return (
    <div>
      <h1>Profile: {user.username}</h1>
      {/* 如果这里渲染了 secretKey,说明防御失效 */}
      {/* <p>Key: {user.secretKey}</p> */}
    </div>
  );
}

修改 页面组件,获取数据并传递给 ProfileClient

// app/page.tsx
import { getUserData } from './server-action';
import ProfileClient from './components/ProfileClient';

export default async function Page() {
  const user = await getUserData();

  // 尝试直接传递整个 user 对象
  // React 会检测到 user.secretKey 已被“污染”,并在此处抛出错误
  return <ProfileClient user={user} />;
}

此时运行应用,React 会报错,提示试图将一个被“污染”的值传递给客户端。

4. 清理数据并正确传递

由于 React 阻止了整个对象的传递(因为它包含了被污染的属性),必须将敏感数据从对象中剔除,仅保留客户端需要的公开数据,才能正常渲染。

修改 getUserData 函数,在返回数据前解构过滤 掉敏感字段。

// app/server-action.ts (最终版)
export async function getUserData() {
  const userData = {
    id: 'user_123',
    username: 'alice_dev',
    email: 'alice@example.com',
    secretKey: 'sk_live_51MzQ...' 
  };

  experimental_taintUniqueValue(
    'Do not pass the secret API key to the client.',
    userData.secretKey,
    'SecretKey is leaked in getUserData',
  );

  // 创建一个不包含 secretKey 的新对象
  const { secretKey, ...safeUserData } = userData;

  // 仅返回安全的数据
  return safeUserData;
}

验证 结果。现在 Page.tsx 中的 <ProfileClient user={user} /> 将接收到一个干净的对象,页面可以正常加载,且 secretKey 绝不会出现在浏览器的网络请求或 JavaScript 包中。

5. 针对唯一值的保护特性

experimental_taintUniqueValue 不仅检查值的内容,还会检查值的引用。如果你复制了这个值(例如 const myKey = user.secretKey),新复制的值也会被视为受污染。这对于处理可能被多次引用的敏感对象(如 Error 对象中可能包含请求上下文)非常有用。

测试 引用追踪:假设敏感信息被意外复制到了另一个变量中。

const errorLog = {
  message: 'Login failed',
  // 即使是不同的属性名,只要值引用了 userData.secretKey,也会被拦截
  leakedToken: userData.secretKey 
};

experimental_taintUniqueValue(
  'Do not pass token in error logs',
  userData.secretKey,
  'Token leaked in errorLog'
);

// 如果尝试将 errorLog 传给客户端,同样会报错

这确保了无论敏感数据在对象结构中被移动到哪里,只要其引用被追踪,就无法逃逸到客户端。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文