experimental_taintObjectReference - This feature is available in the latest Experimental version of React

Experimental Feature

此 API 属于实验性功能,尚未在稳定版本的 React 中提供。

你可以通过将 React 包升级到最新的实验版本来尝试:

🌐 You can try it by upgrading React packages to the most recent experimental version:

  • react@experimental
  • react-dom@experimental
  • eslint-plugin-react-hooks@experimental

React 的实验版本可能包含错误。不要在生产环境中使用它们。

🌐 Experimental versions of React may contain bugs. Don’t use them in production.

此 API 仅在 React Server 组件内部可用。

🌐 This API is only available inside React Server Components.

taintObjectReference 让你可以防止将特定对象实例传递给像 user 对象这样的客户端组件。

experimental_taintObjectReference(message, object);

要防止传递密钥、哈希或令牌,请参见 taintUniqueValue

🌐 To prevent passing a key, hash or token, see taintUniqueValue.


参考

🌐 Reference

taintObjectReference(message, object)

使用对象调用 taintObjectReference 来将其注册到 React 中,作为不应直接传递给客户端的内容:

🌐 Call taintObjectReference with an object to register it with React as something that should not be allowed to be passed to the Client as is:

import {experimental_taintObjectReference} from 'react';

experimental_taintObjectReference(
'Do not pass ALL environment variables to the client.',
process.env
);

查看更多示例。

参数

🌐 Parameters

  • message:如果对象被传递到客户端组件,你想要显示的消息。如果对象被传递到客户端组件,这条消息将作为抛出的错误的一部分显示。
  • object:要被污染的对象。函数和类实例可以作为 object 传递给 taintObjectReference。函数和类已经被阻止传递到客户端组件,但 React 的默认错误信息将被你在 message 中定义的内容替代。当一个特定的 Typed Array 实例作为 object 传递给 taintObjectReference 时,Typed Array 的任何其他副本都不会被污染。

返回

🌐 Returns

experimental_taintObjectReference 返回 undefined

注意事项

🌐 Caveats

  • 重新创建或克隆一个被污染的对象会创建一个新的未被污染的对象,该对象可能包含敏感数据。例如,如果你有一个被污染的 user 对象,const userInfo = {name: user.name, ssn: user.ssn}{...user} 将创建新的未被污染的对象。taintObjectReference 仅在对象未经过修改直接传递给客户端组件时防止简单错误。

易犯错误

不要仅依赖标记来保障安全。 对一个对象进行标记并不能阻止所有可能的派生值泄露。例如,被标记对象的克隆会生成一个新的未被标记的对象。使用被标记对象的数据(例如 {secret: taintedObj.secret})会创建一个新的未被标记的值或对象。标记只是保护的一层;一个安全的应用会有多层保护、良好设计的API以及隔离模式。


用法

🌐 Usage

防止用户数据无意中到达客户端

🌐 Prevent user data from unintentionally reaching the client

客户端组件绝不应该接受携带敏感数据的对象。理想情况下,数据获取函数不应暴露当前用户不应访问的数据。有时在重构过程中会发生错误。为了防止这些错误在将来发生,我们可以在我们的数据 API 中“污染”用户对象。

🌐 A Client Component should never accept objects that carry sensitive data. Ideally, the data fetching functions should not expose data that the current user should not have access to. Sometimes mistakes happen during refactoring. To protect against these mistakes happening down the line we can “taint” the user object in our data API.

import {experimental_taintObjectReference} from 'react';

export async function getUser(id) {
const user = await db`SELECT * FROM users WHERE id = ${id}`;
experimental_taintObjectReference(
'Do not pass the entire user object to the client. ' +
'Instead, pick off the specific properties you need for this use case.',
user,
);
return user;
}

现在,每当有人尝试将此对象传递给客户端组件时,都会抛出错误并附带传入的错误消息。

🌐 Now whenever anyone tries to pass this object to a Client Component, an error will be thrown with the passed in error message instead.

深入研究

防止数据获取泄漏

🌐 Protecting against leaks in data fetching

如果你运行的服务器组件环境可以访问敏感数据,则必须小心不要直接传递对象:

🌐 If you’re running a Server Components environment that has access to sensitive data, you have to be careful not to pass objects straight through:

// api.js
export async function getUser(id) {
const user = await db`SELECT * FROM users WHERE id = ${id}`;
return user;
}
import { getUser } from 'api.js';
import { InfoCard } from 'components.js';

export async function Profile(props) {
const user = await getUser(props.userId);
// DO NOT DO THIS
return <InfoCard user={user} />;
}
// components.js
"use client";

export async function InfoCard({ user }) {
return <div>{user.name}</div>;
}

理想情况下,getUser 不应暴露当前用户不应访问的数据。为了防止将 user 对象传递给下游的客户端组件,我们可以“污染”用户对象:

🌐 Ideally, the getUser should not expose data that the current user should not have access to. To prevent passing the user object to a Client Component down the line we can “taint” the user object:

// api.js
import {experimental_taintObjectReference} from 'react';

export async function getUser(id) {
const user = await db`SELECT * FROM users WHERE id = ${id}`;
experimental_taintObjectReference(
'Do not pass the entire user object to the client. ' +
'Instead, pick off the specific properties you need for this use case.',
user,
);
return user;
}

现在,如果有人尝试将 user 对象传递给客户端组件,将会抛出一个带有传入错误信息的错误。

🌐 Now if anyone tries to pass the user object to a Client Component, an error will be thrown with the passed in error message.