taintUniqueValue
允许你防止将唯一值传递给客户端组件,例如密码、密钥或令牌。
¥taintUniqueValue
lets you prevent unique values from being passed to Client Components like passwords, keys, or tokens.
taintUniqueValue(errMessage, lifetime, value)
要防止传递包含敏感数据的对象,请参阅 taintObjectReference
。
¥To prevent passing an object containing sensitive data, see taintObjectReference
.
参考
¥Reference
taintUniqueValue(message, lifetime, value)
使用密码、令牌、密钥或哈希调用 taintUniqueValue
,将其注册到 React,因为不允许将其传递给客户端:
¥Call taintUniqueValue
with a password, token, key or hash to register it with React as something that should not be allowed to be passed to the Client as is:
import {experimental_taintUniqueValue} from 'react';
experimental_taintUniqueValue(
'Do not pass secret keys to the client.',
process,
process.env.SECRET_KEY
);
参数
¥Parameters
-
message
:当value
传递到客户端组件时你想要显示的消息。该消息将作为错误的一部分显示,如果value
传递给客户端组件,则会抛出该错误。¥
message
: The message you want to display ifvalue
is passed to a Client Component. This message will be displayed as a part of the Error that will be thrown ifvalue
is passed to a Client Component. -
lifetime
:指示value
应被污染多长时间的任何对象。当该对象仍然存在时,value
将被阻止发送到任何客户端组件。例如,传递globalThis
会在应用的生命周期内阻止该值。lifetime
通常是一个属性包含value
的对象。¥
lifetime
: Any object that indicates how longvalue
should be tainted.value
will be blocked from being sent to any Client Component while this object still exists. For example, passingglobalThis
blocks the value for the lifetime of an app.lifetime
is typically an object whose properties containsvalue
. -
value
:字符串、bigint 或 TypedArray。value
必须是具有高熵的唯一字符或字节序列,例如加密令牌、私钥、哈希或长密码。value
将被阻止发送到任何客户端组件。¥
value
: A string, bigint or TypedArray.value
must be a unique sequence of characters or bytes with high entropy such as a cryptographic token, private key, hash, or a long password.value
will be blocked from being sent to any Client Component.
返回
¥Returns
experimental_taintUniqueValue
返回 undefined
。
¥experimental_taintUniqueValue
returns undefined
.
注意事项
¥Caveats
-
从受污染的值中衍生出新的值可能会损害对污染的保护。通过大写受污染值、将受污染字符串值连接成更大的字符串、将受污染值转换为 base64、对受污染值进行子字符串化以及其他类似转换创建的新值不会受到污染,除非你对这些新创建的值显式调用
taintUniqueValue
。¥Deriving new values from tainted values can compromise tainting protection. New values created by uppercasing tainted values, concatenating tainted string values into a larger string, converting tainted values to base64, substringing tainted values, and other similar transformations are not tainted unless you explicitly call
taintUniqueValue
on these newly created values. -
不要使用
taintUniqueValue
来保护低熵值,例如 PIN 码或调用号码。如果请求中的任何值由攻击者控制,他们可以通过枚举秘密的所有可能值来推断哪个值被污染。¥Do not use
taintUniqueValue
to protect low-entropy values such as PIN codes or phone numbers. If any value in a request is controlled by an attacker, they could infer which value is tainted by enumerating all possible values of the secret.
用法
¥Usage
防止令牌传递给客户端组件
¥Prevent a token from being passed to Client Components
为了确保密码、会话令牌或其他唯一值等敏感信息不会无意中传递给客户端组件,taintUniqueValue
功能提供了一层保护。当某个值被污染时,任何将其传递给客户端组件的尝试都会导致错误。
¥To ensure that sensitive information such as passwords, session tokens, or other unique values do not inadvertently get passed to Client Components, the taintUniqueValue
function provides a layer of protection. When a value is tainted, any attempt to pass it to a Client Component will result in an error.
lifetime
参数定义该值保持受污染的持续时间。对于应该无限期地保持污染的值,像 globalThis
或 process
这样的对象可以用作 lifetime
参数。这些对象的生命周期跨越应用执行的整个持续时间。
¥The lifetime
argument defines the duration for which the value remains tainted. For values that should remain tainted indefinitely, objects like globalThis
or process
can serve as the lifetime
argument. These objects have a lifespan that spans the entire duration of your app’s execution.
import {experimental_taintUniqueValue} from 'react';
experimental_taintUniqueValue(
'Do not pass a user password to the client.',
globalThis,
process.env.SECRET_KEY
);
如果受污染值的生命周期与某个对象相关联,则 lifetime
应该是封装该值的对象。这确保了受污染的值在封装对象的生命周期内保持受到保护。
¥If the tainted value’s lifespan is tied to a object, the lifetime
should be the object that encapsulates the value. This ensures the tainted value remains protected for the lifetime of the encapsulating object.
import {experimental_taintUniqueValue} from 'react';
export async function getUser(id) {
const user = await db`SELECT * FROM users WHERE id = ${id}`;
experimental_taintUniqueValue(
'Do not pass a user session token to the client.',
user,
user.session.token
);
return user;
}
在此示例中,user
对象充当 lifetime
参数。如果该对象存储在全局缓存中或者可以由另一个请求访问,则会话令牌仍然受到污染。
¥In this example, the user
object serves as the lifetime
argument. If this object gets stored in a global cache or is accessible by another request, the session token remains tainted.
深入研究
¥Using server-only
and taintUniqueValue
to prevent leaking secrets
如果你运行的服务器组件环境可以访问私钥或密码(例如数据库密码),则必须小心不要将其传递给客户端组件。
¥If you’re running a Server Components environment that has access to private keys or passwords such as database passwords, you have to be careful not to pass that to a Client Component.
export async function Dashboard(props) {
// DO NOT DO THIS
return <Overview password={process.env.API_PASSWORD} />;
}
"use client";
import {useEffect} from '...'
export async function Overview({ password }) {
useEffect(() => {
const headers = { Authorization: password };
fetch(url, { headers }).then(...);
}, [password]);
...
}
此示例会将秘密 API 令牌泄露给客户端。如果此 API 令牌可用于访问该特定用户不应访问的数据,则可能会导致数据泄露。
¥This example would leak the secret API token to the client. If this API token can be used to access data this particular user shouldn’t have access to, it could lead to a data breach.
理想情况下,像这样的秘密被抽象到单个辅助程序文件中,该文件只能由服务器上的可信数据实用程序导入。该辅助程序甚至可以用 server-only
标记,以确保该文件不会导入到客户端。
¥Ideally, secrets like this are abstracted into a single helper file that can only be imported by trusted data utilities on the server. The helper can even be tagged with server-only
to ensure that this file isn’t imported on the client.
import "server-only";
export function fetchAPI(url) {
const headers = { Authorization: process.env.API_PASSWORD };
return fetch(url, { headers });
}
有时在重构过程中会发生错误,但并非所有同事都知道这一点。为了防止这种错误发生,我们可以 “taint” 实际密码:
¥Sometimes mistakes happen during refactoring and not all of your colleagues might know about this. To protect against this mistakes happening down the line we can “taint” the actual password:
import "server-only";
import {experimental_taintUniqueValue} from 'react';
experimental_taintUniqueValue(
'Do not pass the API token password to the client. ' +
'Instead do all fetches on the server.'
process,
process.env.API_PASSWORD
);
现在,每当有人尝试将此密码传递给客户端组件,或使用服务器操作将密码发送给客户端组件时,都会抛出一条错误,并显示你在调用 taintUniqueValue
时定义的消息。
¥Now whenever anyone tries to pass this password to a Client Component, or send the password to a Client Component with a Server Action, an error will be thrown with message you defined when you called taintUniqueValue
.