experimental_taintObjectReference
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(汚染)するオブジェクト。関数やクラスインスタンスもtaintObjectReferenceにobjectとして渡すことができます。関数やクラスはクライアントコンポーネントに渡せないよう元々ブロックされていますが、React のデフォルトのエラーメッセージをmessageで定義したものに置き換えられます。Typed Array の特定のインスタンスをtaintObjectReferenceにobjectとして渡した場合、その Typed Array の他のコピーは taint されません。
返り値
experimental_taintObjectReference は undefined を返します。
注意点
- taint されたオブジェクトを再作成またはクローンすると、機密データを含む可能性がある新しい taint されていないオブジェクトが作成されます。例えば、taint された
userオブジェクトがある場合、const userInfo = {name: user.name, ssn: user.ssn}や{...user}は taint されていない新しいオブジェクトを作成します。taintObjectReferenceが保護するのは、オブジェクトが変更されずにクライアントコンポーネントへそのまま渡されてしまうような単純なミスだけです。
使用法
ユーザデータが意図せずクライアントに到達するのを防ぐ
クライアントコンポーネントは、機密データを持つオブジェクトを決して受け取るべきではありません。理想的には、データ取得関数は現在のユーザに見せるべきではないデータを公開しないようにするべきです。しかしリファクタリング中にミスが起きることもあります。後続の処理でそのようなミスが起きた場合に備えて、データ 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 オブジェクトをクライアントコンポーネントに渡そうとすると、指定したエラーメッセージを含むエラーがスローされます。