Tainting (Markierung sensibler Daten)
Verwendung
Die taint
-Option ermöglicht die Nutzung experimenteller React-APIs zur Markierung von Objekten und Werten als sensibel. Diese Funktion hilft, das versehentliche Übergeben sensibler Daten an den Client zu verhindern. Wenn aktiviert, können Sie folgende APIs verwenden:
experimental_taintObjectReference
zum Markieren von Objektreferenzen.experimental_taintUniqueValue
zum Markieren einzigartiger Werte.
Wichtig: Durch Aktivieren dieser Option wird auch der React
experimental
-Channel für dasapp
-Verzeichnis aktiviert.
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
taint: true,
},
}
export default nextConfig
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
taint: true,
},
}
module.exports = nextConfig
Warnung: Verlassen Sie sich nicht ausschließlich auf die Tainting-API, um das Offenlegen sensibler Daten an den Client zu verhindern. Siehe unsere Sicherheitsempfehlungen.
Die Tainting-APIs ermöglichen eine defensive Programmierung, indem Daten deklarativ und explizit markiert werden, die nicht die Server-Client-Grenze überschreiten dürfen. Wenn ein Objekt oder Wert diese Grenze passiert, wirft React einen Fehler.
Dies ist hilfreich in folgenden Fällen:
- Die Methoden zum Lesen der Daten liegen außerhalb Ihrer Kontrolle
- Sie müssen mit sensiblen Datenstrukturen arbeiten, die nicht von Ihnen definiert wurden
- Sensible Daten werden während des Renderings von Server-Komponenten abgerufen
Es wird empfohlen, Ihre Datenmodelle und APIs so zu gestalten, dass sensible Daten nicht in Kontexte zurückgegeben werden, wo sie nicht benötigt werden.
Einschränkungen
- Tainting kann Objekte nur über Referenzen verfolgen. Das Kopieren eines Objekts erstellt eine unmarkierte Version, die alle Garantien der API verliert. Sie müssen die Kopie erneut markieren.
- Tainting kann keine abgeleiteten Daten von einem markierten Wert verfolgen. Sie müssen auch den abgeleiteten Wert markieren.
- Werte bleiben markiert, solange ihre Referenz im Gültigkeitsbereich ist. Siehe die
experimental_taintUniqueValue
Parameter-Referenz für weitere Informationen.
Beispiele
Markieren einer Objektreferenz
In diesem Fall gibt die getUserDetails
-Funktion Daten über einen bestimmten Benutzer zurück. Wir markieren die Benutzerobjektreferenz, damit sie nicht die Server-Client-Grenze überschreiten kann. Angenommen, UserCard
ist eine Client-Komponente.
import { experimental_taintObjectReference } from 'react'
function getUserDetails(id: string): UserDetails {
const user = await db.queryUserById(id)
experimental_taintObjectReference(
'Verwenden Sie nicht das gesamte Benutzerinfo-Objekt. Wählen Sie stattdessen nur die benötigten Felder aus.',
user
)
return user
}
import { experimental_taintObjectReference } from 'react'
function getUserDetails(id) {
const user = await db.queryUserById(id)
experimental_taintObjectReference(
'Verwenden Sie nicht das gesamte Benutzerinfo-Objekt. Wählen Sie stattdessen nur die benötigten Felder aus.',
user
)
return user
}
Wir können weiterhin einzelne Felder des markierten userDetails
-Objekts abrufen.
export async function ContactPage({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
const userDetails = await getUserDetails(id)
return (
<UserCard
firstName={userDetails.firstName}
lastName={userDetails.lastName}
/>
)
}
export async function ContactPage({ params }) {
const { id } = await params
const userDetails = await getUserDetails(id)
return (
<UserCard
firstName={userDetails.firstName}
lastName={userDetails.lastName}
/>
)
}
Das Übergeben des gesamten Objekts an die Client-Komponente wirft nun einen Fehler.
export async function ContactPage({
params,
}: {
params: Promise<{ id: string }>
}) {
const userDetails = await getUserDetails(id)
// Wirft einen Fehler
return <UserCard user={userDetails} />
}
export async function ContactPage({ params }) {
const { id } = await params
const userDetails = await getUserDetails(id)
// Wirft einen Fehler
return <UserCard user={userDetails} />
}
Markieren eines einzigartigen Werts
In diesem Fall können wir die Server-Konfiguration durch Aufrufe von config.getConfigDetails
abrufen. Die Systemkonfiguration enthält jedoch den SERVICE_API_KEY
, den wir nicht an Clients weitergeben möchten.
Wir können den Wert config.SERVICE_API_KEY
markieren.
import { experimental_taintUniqueValue } from 'react'
function getSystemConfig(): SystemConfig {
const config = await config.getConfigDetails()
experimental_taintUniqueValue(
'Konfigurations-Tokens nicht an den Client übergeben',
config,
config.SERVICE_API_KEY
)
return config
}
import { experimental_taintUniqueValue } from 'react'
function getSystemConfig() {
const config = await config.getConfigDetails()
experimental_taintUniqueValue(
'Konfigurations-Tokens nicht an den Client übergeben',
config,
config.SERVICE_API_KEY
)
return config
}
Wir können weiterhin andere Eigenschaften des systemConfig
-Objekts abrufen.
export async function Dashboard() {
const systemConfig = await getSystemConfig()
return <ClientDashboard version={systemConfig.SERVICE_API_VERSION} />
}
Das Übergeben von SERVICE_API_KEY
an ClientDashboard
wirft jedoch einen Fehler.
export async function Dashboard() {
const systemConfig = await getSystemConfig()
// Jemand macht einen Fehler in einem PR
const version = systemConfig.SERVICE_API_KEY
return <ClientDashboard version={version} />
}
Beachten Sie, dass selbst wenn systemConfig.SERVICE_API_KEY
einer neuen Variable zugewiesen wird, das Übergeben an eine Client-Komponente weiterhin einen Fehler verursacht.
Ein von einem markierten Wert abgeleiteter Wert wird jedoch an den Client übergeben.
export async function Dashboard() {
const systemConfig = await getSystemConfig()
// Jemand macht einen Fehler in einem PR
const version = `version::${systemConfig.SERVICE_API_KEY}`
return <ClientDashboard version={version} />
}
Ein besserer Ansatz ist, SERVICE_API_KEY
aus den von getSystemConfig
zurückgegebenen Daten zu entfernen.