Skip to content

taint

用法

¥Usage

taint 选项支持实验性的 React API,用于污染对象和值。此功能有助于防止敏感数据意外传递给客户端。启用后,你可以使用:

¥The taint option enables support for experimental React APIs for tainting objects and values. This feature helps prevent sensitive data from being accidentally passed to the client. When enabled, you can use:

需要了解:激活此标志还会为 app 目录启用 React experimental 通道。

¥Good to know: Activating this flag also enables the React experimental channel for app directory.

ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  experimental: {
    taint: true,
  },
}

export default nextConfig

警告:不要依赖污点 API 作为防止敏感数据暴露给客户端的唯一机制。查看我们的 安全建议

¥Warning: Do not rely on the taint API as your only mechanism to prevent exposing sensitive data to the client. See our security recommendations.

污点 API 允许你通过声明式显式标记不允许通过服务器-客户端边界的数据来采取防御措施。当对象或值跨越服务器-客户端边界时,React 会抛出错误。

¥The taint APIs allows you to be defensive, by declaratively and explicitly marking data that is not allowed to pass through the Server-Client boundary. When an object or value, is passed through the Server-Client boundary, React throws an error.

这在以下情况下很有用:

¥This is helpful for cases where:

  • 读取数据的方法不受你控制

    ¥The methods to read data are out of your control

  • 你必须处理未由你定义的敏感数据形状。

    ¥You have to work with sensitive data shapes not defined by you

  • 服务器组件渲染期间会访问敏感数据

    ¥Sensitive data is accessed during Server Component rendering

建议对数据和 API 进行建模,以免敏感数据返回到不需要的上下文。

¥It is recommended to model your data and APIs so that sensitive data is not returned to contexts where it is not needed.

注意事项

¥Caveats

  • 污染只能通过引用跟踪对象。复制对象会创建一个未受污染的版本,这将失去 API 提供的所有保证。你需要污染副本。

    ¥Tainting can only keep track of objects by reference. Copying an object creates an untainted version, which loses all guarantees given by the API. You'll need to taint the copy.

  • 污染无法跟踪从受污染值派生的数据。你还需要污染派生值。

    ¥Tainting cannot keep track of data derived from a tainted value. You also need to taint the derived value.

  • 只要值的生命周期引用在作用域内,它们就会受到污染。有关更多信息,请参阅 experimental_taintUniqueValue 参数参考

    ¥Values are tainted for as long as their lifetime reference is within scope. See the experimental_taintUniqueValue parameters reference, for more information.

示例

¥Examples

污染对象引用

¥Tainting an object reference

在本例中,getUserDetails 函数返回给定用户的数据。我们会污染用户对象引用,使其无法跨越服务器-客户端边界。例如,假设 UserCard 是客户端组件。

¥In this case, the getUserDetails function returns data about a given user. We taint the user object reference, so that it cannot cross a Server-Client boundary. For example, assuming UserCard is a Client Component.

ts
import { experimental_taintObjectReference } from 'react'

function getUserDetails(id: string): UserDetails {
  const user = await db.queryUserById(id)

  experimental_taintObjectReference(
    'Do not use the entire user info object. Instead, select only the fields you need.',
    user
  )

  return user
}

我们仍然可以访问受污染的 userDetails 对象中的各个字段。

¥We can still access individual fields from the tainted userDetails object.

tsx
export async function ContactPage({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = await params
  const userDetails = await getUserDetails(id)

  return (
    <UserCard
      firstName={userDetails.firstName}
      lastName={userDetails.lastName}
    />
  )
}

现在,将整个对象传递给客户端组件将抛出错误。

¥Now, passing the entire object to the Client Component will throw an error.

tsx
export async function ContactPage({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const userDetails = await getUserDetails(id)

  // Throws an error
  return <UserCard user={userDetails} />
}

污染唯一值

¥Tainting a unique value

在本例中,我们可以通过等待对 config.getConfigDetails 的调用来访问服务器配置。但是,系统配置包含我们不想暴露给客户端的 SERVICE_API_KEY

¥In this case, we can access the server configuration by awaiting calls to config.getConfigDetails. However, the system configuration contains the SERVICE_API_KEY that we don't want to expose to clients.

我们可以污染 config.SERVICE_API_KEY 的值。

¥We can taint the config.SERVICE_API_KEY value.

ts
import { experimental_taintUniqueValue } from 'react'

function getSystemConfig(): SystemConfig {
  const config = await config.getConfigDetails()

  experimental_taintUniqueValue(
    'Do not pass configuration tokens to the client',
    config,
    config.SERVICE_API_KEY
  )

  return config
}

我们仍然可以访问 systemConfig 对象的其他属性。

¥We can still access other properties of the systemConfig object.

tsx
export async function Dashboard() {
  const systemConfig = await getSystemConfig()

  return <ClientDashboard version={systemConfig.SERVICE_API_VERSION} />
}

但是,将 SERVICE_API_KEY 传递给 ClientDashboard 会引发错误。

¥However, passing SERVICE_API_KEY to ClientDashboard throws an error.

tsx
export async function Dashboard() {
  const systemConfig = await getSystemConfig()
  // Someone makes a mistake in a PR
  const version = systemConfig.SERVICE_API_KEY

  return <ClientDashboard version={version} />
}

请注意,即使如此,systemConfig.SERVICE_API_KEY 仍会被重新赋值给一个新变量。将其传递给客户端组件仍然会抛出错误。

¥Note that, even though, systemConfig.SERVICE_API_KEY is reassigned to a new variable. Passing it to a Client Component still throws an error.

然而,从受污染的唯一值派生的值将暴露给客户端。

¥Whereas, a value derived from a tainted unique value, will be exposed to the client.

tsx
export async function Dashboard() {
  const systemConfig = await getSystemConfig()
  // Someone makes a mistake in a PR
  const version = `version::${systemConfig.SERVICE_API_KEY}`

  return <ClientDashboard version={version} />
}

更好的方法是从 getSystemConfig 返回的数据中删除 SERVICE_API_KEY

¥A better approach is to remove SERVICE_API_KEY from the data returned by getSystemConfig.