taintUniqueValue
を使用すると、パスワード、キー、トークンなど、一意の値がクライアントコンポーネントに渡されるのを防ぐことができます。
taintUniqueValue(errMessage, lifetime, value)
機密データを含むオブジェクトの受け渡しを防ぐには、taintObjectReference
を参照してください。
リファレンス
taintUniqueValue(message, lifetime, value)
パスワード、トークン、キー、またはハッシュを使用してtaintUniqueValue
を呼び出すと、クライアントにそのまま渡してはならないものとしてReactに登録されます
import {experimental_taintUniqueValue} from 'react';
experimental_taintUniqueValue(
'Do not pass secret keys to the client.',
process,
process.env.SECRET_KEY
);
パラメータ
-
message
:value
がクライアントコンポーネントに渡された場合に表示するメッセージ。value
がクライアントコンポーネントに渡された場合にスローされるエラーの一部として、このメッセージが表示されます。 -
lifetime
:value
をどのくらいの期間汚染する必要があるかを示すオブジェクト。value
はこのオブジェクトが存在する限り、クライアントコンポーネントに送信されるのをブロックされます。たとえば、globalThis
を渡すと、アプリの存続期間中、値がブロックされます。lifetime
は通常、プロパティにvalue
を含むオブジェクトです。 -
value
: 文字列、bigint、またはTypedArray。暗号トークン、秘密鍵、ハッシュ、または長いパスワードなど、エントロピーの高い一意の文字またはバイトシーケンスである必要があります。value
は、クライアントコンポーネントに送信されるのをブロックされます。
戻り値
experimental_taintUniqueValue
はundefined
を返します。
注意点 ...
- 汚染された値から新しい値を派生させると、汚染保護が損なわれる可能性があります。汚染された値を大文字にする、汚染された文字列値を連結してより大きな文字列にする、汚染された値をbase64に変換する、汚染された値を部分文字列にする、およびその他の同様の変換によって作成された新しい値は、これらの新しく作成された値に対して明示的に
taintUniqueValue
を呼び出さない限り、汚染されません。 - PINコードや電話番号などの低エントロピー値を保護するために、
taintUniqueValue
を使用しないでください。リクエスト内のいずれかの値が攻撃者によって制御されている場合、攻撃者はシークレットのすべての可能な値を列挙することで、どの値が汚染されているかを推測する可能性があります。
使用方法 ...
クライアントコンポーネントへのトークンの受け渡しを防ぐ ...
パスワード、セッション トークン、またはその他の固有の値などの機密情報が誤ってクライアント コンポーネントに渡されないようにするために、taintUniqueValue
関数は保護レイヤーを提供します。値が汚染されている場合、クライアント コンポーネントに渡そうとするとエラーが発生します。
lifetime
引数は、値が汚染されたままになる期間を定義します。無期限に汚染されたままにする必要がある値の場合、globalThis
やprocess
のようなオブジェクトをlifetime
引数として使用できます。これらのオブジェクトは、アプリの実行全体にわたる寿命を持ちます。
import {experimental_taintUniqueValue} from 'react';
experimental_taintUniqueValue(
'Do not pass a user password to the client.',
globalThis,
process.env.SECRET_KEY
);
汚染された値の寿命がオブジェクトに関連付けられている場合、lifetime
は値をカプセル化するオブジェクトである必要があります。これにより、汚染された値はカプセル化オブジェクトの寿命の間、保護されたままになります。
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
引数として機能します。このオブジェクトがグローバルキャッシュに格納されるか、別のリクエストからアクセスできる場合、セッショントークンは汚染されたままになります。
詳細
シークレットの漏洩を防ぐためのserver-only
とtaintUniqueValue
の使用 ...
シークレットの漏洩を防ぐためのserver-only
とtaintUniqueValue
の使用 ...
データベースパスワードなどの秘密鍵またはパスワードにアクセスできるサーバーコンポーネント環境を実行している場合は、それをクライアントコンポーネントに渡さないように注意する必要があります。
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トークンを使用して、この特定のユーザーがアクセスすべきでないデータにアクセスできる場合、データ侵害につながる可能性があります。
理想的には、このようなシークレットは、サーバー上の信頼できるデータユーティリティによってのみインポートできる単一のヘルパーファイルに抽象化されます。ヘルパーには、このファイルがクライアントにインポートされないようにするために、server-only
のタグを付けることもできます。
import "server-only";
export function fetchAPI(url) {
const headers = { Authorization: process.env.API_PASSWORD };
return fetch(url, { headers });
}
リファクタリング中にミスが発生することがあり、すべての同僚がこのことについて知っているとは限りません。将来発生する可能性のあるこのようなミスを防ぐために、実際のパスワードを「汚染」することができます。
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` を呼び出したときに定義したメッセージと共にエラーがスローされます。