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

実験的機能

この API は実験的なものであり、まだ安定版の React では利用できません。

React パッケージを最新の実験バージョンにアップグレードすることで試すことができます。

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

React の実験バージョンにはバグが含まれている可能性があります。本番環境では使用しないでください。

この API は React Server Components 内でのみ利用できます。

taintObjectReference を使うと、user オブジェクトのような特定のオブジェクトインスタンスがクライアントコンポーネントに渡されるのを防げます。

experimental_taintObjectReference(message, object);

キー、ハッシュ、トークンなどが渡されるのを防ぎたい場合は、taintUniqueValue を参照してください。


リファレンス

taintObjectReference(message, object)

taintObjectReference をオブジェクトと共に呼び出すことで、そのオブジェクトをクライアントにそのまま渡してはならないものとして React に登録します。

import {experimental_taintObjectReference} from 'react';

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

さらに例を見る

引数

  • message: オブジェクトがクライアントコンポーネントに渡されようとした場合に表示したいメッセージ。このメッセージは、そのオブジェクトがクライアントコンポーネントに渡されようとした際にスローされるエラーの一部として表示されます。

  • object: taint(汚染)するオブジェクト。関数やクラスインスタンスも taintObjectReferenceobject として渡すことができます。関数やクラスはクライアントコンポーネントに渡せないよう元々ブロックされていますが、React のデフォルトのエラーメッセージを message で定義したものに置き換えられます。Typed Array の特定のインスタンスを taintObjectReferenceobject として渡した場合、その Typed Array の他のコピーは taint されません。

返り値

experimental_taintObjectReferenceundefined を返します。

注意点

  • taint されたオブジェクトを再作成またはクローンすると、機密データを含む可能性がある新しい taint されていないオブジェクトが作成されます。例えば、taint された user オブジェクトがある場合、const userInfo = {name: user.name, ssn: user.ssn}{...user} は taint されていない新しいオブジェクトを作成します。taintObjectReference が保護するのは、オブジェクトが変更されずにクライアントコンポーネントへそのまま渡されてしまうような単純なミスだけです。

落とし穴

セキュリティを taint だけに頼らないでください。オブジェクトを taint しても、そこから派生しうるあらゆる値の漏洩を防げるわけではありません。例えば、taint されたオブジェクトをクローンすると、taint されていない新しいオブジェクトが作成されます。taint されたオブジェクトのデータを使って(例えば {secret: taintedObj.secret})、taint されていない新しい値やオブジェクトが作成できます。taint は保護層の 1 つです。セキュアなアプリには、複数の保護層、適切に設計された API、分離パターンが必要です。


使用法

ユーザデータが意図せずクライアントに到達するのを防ぐ

クライアントコンポーネントは、機密データを持つオブジェクトを決して受け取るべきではありません。理想的には、データ取得関数は現在のユーザに見せるべきではないデータを公開しないようにするべきです。しかしリファクタリング中にミスが起きることもあります。後続の処理でそのようなミスが起きた場合に備えて、データ API 内で user オブジェクトを “taint”(汚染)できます。

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;
}

これにより、誰かがこのオブジェクトをクライアントコンポーネントに渡そうとすると、指定したエラーメッセージを含むエラーがスローされます。

さらに深く知る

データ取得での漏えいを防ぐ

機密データにアクセスできるサーバコンポーネント環境を利用している場合、オブジェクトをそのまま渡さないように注意する必要があります。

// 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 オブジェクトがクライアントコンポーネントに渡されるのを防ぐために、user オブジェクトを “taint” できます。

// 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 オブジェクトをクライアントコンポーネントに渡そうとすると、指定したエラーメッセージを含むエラーがスローされます。