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 必須是具有高熵的唯一字元或位元組序列,例如加密權杖、私鑰、雜湊或長密碼。value 將被阻止傳送到任何客戶端元件。

回傳值

experimental_taintUniqueValue 會回傳 undefined

注意事項

  • 從受污染的值衍生新的值可能會損害污染保護。透過將受污染的值轉換為大寫、將受污染的字串值串接成更大的字串、將受污染的值轉換為 base64、取得受污染值的子字串以及其他類似的轉換所建立的新值,除非您明確地在這些新建立的值上呼叫 taintUniqueValue,否則它們不會被污染。
  • 不要使用 taintUniqueValue 來保護低熵值,例如 PIN 碼或電話號碼。如果請求中的任何值是由攻擊者控制的,他們可以透過列舉機密的可能值來推斷哪個值受到污染。

用法

防止 Token 傳遞到客戶端組件

為了確保敏感資訊(例如密碼、會話 Token 或其他唯一值)不會意外傳遞到客戶端組件,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 參數。如果此物件儲存在全域快取中或可被另一個請求存取,則會話 Token 將保持受污染狀態。

陷阱

不要僅僅依賴污染來確保安全。污染一個值並不能阻止所有可能的衍生值。例如,透過將受污染的字串轉換為大寫來建立新值,並不會污染新值。

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 被污染。然後透過在 password 上呼叫 toUpperCase 方法,使用 password 建立一個新的值 uppercasePassword。新建立的 uppercasePassword 不會被污染。

其他類似從受污染值衍生新值的方法,例如將其串連成更大的字串、將其轉換為 base64 或傳回子字串,都會建立未受污染的值。

污染機制僅能防止簡單的錯誤,例如將機密值明確傳遞給客戶端。呼叫 taintUniqueValue 時的錯誤,例如在 React 之外使用全域儲存區,而沒有相應的 lifetime 物件,可能會導致受污染的值變為未受污染。污染是一種保護層;一個安全的應用程式將具有多層保護、精心設計的 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 Token 洩漏給客戶端。如果此 API Token 可用於存取此特定使用者不應存取的資料,則可能導致資料外洩。

理想情況下,此類機密應抽象化到一個單獨的輔助程式檔案中,該檔案只能由伺服器上受信任的資料工具匯入。甚至可以使用 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 時定義的訊息。