taintUniqueValue מאפשרת למנוע העברה של ערכים ייחודיים ל-Client Components, כמו סיסמאות, מפתחות או tokens.
taintUniqueValue(errMessage, lifetime, value)כדי למנוע העברה של אובייקט שמכיל מידע רגיש, ראו taintObjectReference.
Reference
taintUniqueValue(message, lifetime, value)
קראו ל-taintUniqueValue עם סיסמה, token, מפתח או hash כדי לרשום אותם ב-React כמשהו שאסור להעביר ללקוח כפי שהוא:
import {experimental_taintUniqueValue} from 'react';
experimental_taintUniqueValue(
'Do not pass secret keys to the client.',
process,
process.env.SECRET_KEY
);Parameters
-
message: ההודעה שתרצו להציג אםvalueמועבר ל-Client Component. הודעה זו תוצג כחלק מה-Error שיושלך אםvalueמועבר ל-Client Component. -
lifetime: כל אובייקט שמציין כמה זמןvalueצריך להיות מסומן כ-tainted.valueייחסם משליחה לכל Client Component כל עוד האובייקט הזה עדיין קיים. לדוגמה, העברתglobalThisחוסמת את הערך לאורך כל חיי האפליקציה. לרובlifetimeהוא אובייקט שהמאפיינים שלו מכילים אתvalue. -
value: מחרוזת, bigint או TypedArray.valueחייב להיות רצף ייחודי של תווים או בתים עם אנטרופיה גבוהה, כמו token קריפטוגרפי, מפתח פרטי, hash או סיסמה ארוכה.valueייחסם משליחה לכל Client Component.
Returns
experimental_taintUniqueValue מחזירה undefined.
Caveats
- גזירת ערכים חדשים מערכים tainted עלולה לפגוע בהגנת tainting. ערכים חדשים שנוצרים מהמרת אותיות לגדולות, שרשור מחרוזות tainted למחרוזת גדולה יותר, המרה ל-base64, חיתוך תת-מחרוזת מערכים tainted וטרנספורמציות דומות, אינם tainted אלא אם קוראים במפורש ל-
taintUniqueValueגם על הערכים החדשים. - אל תשתמשו ב-
taintUniqueValueלהגנה על ערכים בעלי אנטרופיה נמוכה כמו קודי PIN או מספרי טלפון. אם ערך כלשהו בבקשה נשלט על ידי תוקף, הוא עלול להסיק איזה ערך מסומן כ-tainted על ידי מעבר על כל הערכים האפשריים של הסוד.
שימוש
מניעת העברת token ל-Client Components
כדי לוודא שמידע רגיש כמו סיסמאות, session tokens או ערכים ייחודיים אחרים לא מועבר בטעות ל-Client Components, הפונקציה taintUniqueValue מספקת שכבת הגנה. כשערך מסומן כ-tainted, כל ניסיון להעביר אותו ל-Client Component יגרום לשגיאה.
הארגומנט lifetime מגדיר את משך הזמן שבו הערך נשאר tainted. לערכים שצריכים להישאר tainted ללא הגבלת זמן, אובייקטים כמו 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. אם האובייקט הזה נשמר ב-global cache או נגיש מבקשה אחרת, ה-session token נשאר tainted.
Deep Dive
אם אתם מריצים סביבת Server Components שיש לה גישה למפתחות פרטיים או סיסמאות, כמו סיסמת מסד נתונים, צריך להיזהר לא להעביר את זה ל-Client Component.
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 ללקוח. אם ה-token הזה יכול לשמש לגישה לנתונים שלמשתמש הזה לא אמורה להיות גישה אליהם, זה עלול להוביל לדליפת מידע.
אידיאלית, סודות כאלה יופשטו לקובץ helper יחיד שאפשר לייבא רק מתוך utilities מהימנים בצד השרת. אפשר אפילו לתייג את ה-helper עם server-only כדי להבטיח שהקובץ הזה לא מיובא ללקוח.
import "server-only";
export function fetchAPI(url) {
const headers = { Authorization: process.env.API_PASSWORD };
return fetch(url, { headers });
}לפעמים קורות טעויות במהלך refactoring ולא כל חברי הצוות מודעים לכך. כדי להתגונן מפני טעויות כאלה בהמשך, אפשר “לסמן” את הסיסמה עצמה:
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
);כעת, בכל פעם שמישהו ינסה להעביר את הסיסמה הזו ל-Client Component, או לשלוח אותה ל-Client Component דרך Server Action, תיזרק שגיאה עם ההודעה שהגדרתם בקריאה ל-taintUniqueValue.