experimental_taintUniqueValue

工事中

このAPIは実験的であり、Reactの安定バージョンではまだ利用できません。

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

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

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

このAPIは、Reactサーバーコンポーネント内でのみ使用できます。

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_taintUniqueValueundefinedを返します。

注意点 ...

  • 汚染された値から新しい値を派生させると、汚染保護が損なわれる可能性があります。汚染された値を大文字にする、汚染された文字列値を連結してより大きな文字列にする、汚染された値をbase64に変換する、汚染された値を部分文字列にする、およびその他の同様の変換によって作成された新しい値は、これらの新しく作成された値に対して明示的にtaintUniqueValueを呼び出さない限り、汚染されません。
  • PINコードや電話番号などの低エントロピー値を保護するために、taintUniqueValueを使用しないでください。リクエスト内のいずれかの値が攻撃者によって制御されている場合、攻撃者はシークレットのすべての可能な値を列挙することで、どの値が汚染されているかを推測する可能性があります。

使用方法 ...

クライアントコンポーネントへのトークンの受け渡しを防ぐ ...

パスワード、セッション トークン、またはその他の固有の値などの機密情報が誤ってクライアント コンポーネントに渡されないようにするために、taintUniqueValue 関数は保護レイヤーを提供します。値が汚染されている場合、クライアント コンポーネントに渡そうとするとエラーが発生します。

lifetime引数は、値が汚染されたままになる期間を定義します。無期限に汚染されたままにする必要がある値の場合、globalThisprocessのようなオブジェクトを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引数として機能します。このオブジェクトがグローバルキャッシュに格納されるか、別のリクエストからアクセスできる場合、セッショントークンは汚染されたままになります。

落とし穴

セキュリティのために汚染のみに依存しないでください。 値を汚染しても、すべての可能な派生値がブロックされるわけではありません。たとえば、汚染された文字列を大文字にすることによって新しい値を作成しても、新しい値は汚染されません。

import {experimental_taintUniqueValue} from 'react';

const password = 'correct horse battery staple';

experimental_taintUniqueValue(
'Do not pass the password to the client.',
globalThis,
password
);

const uppercasePassword = password.toUpperCase() // `uppercasePassword` is not tainted

この例では、定数passwordは汚染されています。次に、passwordtoUpperCaseメソッドを呼び出すことにより、passwordを使用して新しい値uppercasePasswordが作成されます。新しく作成されたuppercasePasswordは汚染されていません。

より大きな文字列に連結する、base64に変換する、部分文字列を返すなど、汚染された値から新しい値を派生させる他の同様の方法では、汚染されていない値が作成されます。

汚染は、シークレット値をクライアントに明示的に渡すなどの単純なミスを防ぐだけです。対応するライフタイムオブジェクトなしで、Reactの外部のグローバルストアを使用するなど、taintUniqueValueの呼び出しにおけるミスは、汚染された値が汚染されていない状態になる可能性があります。汚染は保護レイヤーです。安全なアプリには、複数の保護レイヤー、適切に設計されたAPI、および分離パターンがあります。

詳細

シークレットの漏洩を防ぐためのserver-onlytaintUniqueValueの使用 ...

データベースパスワードなどの秘密鍵またはパスワードにアクセスできるサーバーコンポーネント環境を実行している場合は、それをクライアントコンポーネントに渡さないように注意する必要があります。

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` を呼び出したときに定義したメッセージと共にエラーがスローされます。