experimental_taintUniqueValue

๊ฐœ๋ฐœ์ค‘์ด์—์š”

์ด API๋Š” ์‹คํ—˜์ ์ด๋ฉฐ React ์•ˆ์ • ๋ฒ„์ „์—์„œ๋Š” ์•„์ง ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด API๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด React ํŒจํ‚ค์ง€๋ฅผ ๊ฐ€์žฅ ์ตœ๊ทผ์˜ ์‹คํ—˜์ ์ธ ๋ฒ„์ „์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

์‹คํ—˜์ ์ธ ๋ฒ„์ „์˜ React์—๋Š” ๋ฒ„๊ทธ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”.

์ด API๋Š” React Server Components์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

taintUniqueValue๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŒจ์Šค์›Œ๋“œ, ํ‚ค ๋˜๋Š” ํ† ํฐ๊ณผ ๊ฐ™์€ ๊ณ ์œ  ๊ฐ’์„ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „์†กํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

taintUniqueValue(errMessage, lifetime, value)

๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋œ ๊ฐ์ฒด๊ฐ€ ์ „๋‹ฌ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ taintObjectReference๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.


๋ ˆํผ๋Ÿฐ์Šค

taintUniqueValue(message, lifetime, value)

ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌ๋˜์ง€ ์•Š์•„์•ผ ํ•  ํŒจ์Šค์›Œ๋“œ, ํ† ํฐ, ํ‚ค ๋˜๋Š” ํ•ด์‹œ๋ฅผ taintUniqueValue์™€ ํ•จ๊ป˜ ํ˜ธ์ถœํ•˜์—ฌ React์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

import {experimental_taintUniqueValue} from 'react';

experimental_taintUniqueValue(
'์‹œํฌ๋ฆฟ ํ‚ค๋ฅผ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌํ•˜์ง€ ๋งˆ์„ธ์š”.',
process,
process.env.SECRET_KEY
);

๋” ๋งŽ์€ ์˜ˆ์ œ๋ฅผ ์•„๋ž˜์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜

  • message: ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์— value๊ฐ€ ์ „๋‹ฌ๋  ๊ฒฝ์šฐ ํ‘œ์‹œํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค. ์ด ๋ฉ”์‹œ์ง€๋Š” value๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋  ๊ฒฝ์šฐ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜์˜ ์ผ๋ถ€๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

  • lifetime: value๊ฐ€ ์–ผ๋งˆ๋‚˜ ์˜ค๋žซ๋™์•ˆ ์˜ค์—ผ(taint) ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.value๋Š” ์ด ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•˜๋Š” ๋™์•ˆ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌ๋˜์ง€ ์•Š๋„๋ก ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด globalThis๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ์•ฑ์ด ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ฐ’์ด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. lifetime์€ ์ผ๋ฐ˜์ ์œผ๋กœ value๋ฅผ ํ”„๋กœํผํ‹ฐ๋กœ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

  • value: string, bigint ๋˜๋Š” TypedArray์ž…๋‹ˆ๋‹ค. value๋Š” ์•”ํ˜ธํ™” ํ† ํฐ, ๊ฐœ์ธ ํ‚ค, ํ•ด์‹œ ๋˜๋Š” ๊ธด ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ๊ฐ™์ด ๋†’์€ ์—”ํŠธ๋กœํ”ผ๋ฅผ ๊ฐ€์ง„ ๊ณ ์œ ํ•œ ๋ฌธ์ž ๋˜๋Š” ๋ฐ”์ดํŠธ ์‹œํ€€์Šค์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. value๋Š” ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „์†ก๋˜์ง€ ์•Š๋„๋ก ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

experimental_taintUniqueValue๋Š” undefined๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • ์˜ค์—ผ๋œ ๊ฐ’์„ ์ด์šฉํ•ด์„œ ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋งŒ๋“ค์–ด ๋‚ด๋ฉด ์˜ค์—ผ ๋ณดํ˜ธ๊ฐ€ ์†์ƒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค์—ผ๋œ ๊ฐ’์„ ๋Œ€๋ฌธ์ž๋กœ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ๋ฌธ์ž์—ด๊ณผ ์—ฐ๊ฒฐํ•˜๊ฑฐ๋‚˜, base64๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜, ์ž˜๋ผ๋‚ด๋Š” ๋“ฑ ๊ธฐํƒ€ ์œ ์‚ฌํ•œ ๋ณ€ํ™˜์„ ํ†ตํ•ด์„œ ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑ๋œ ๊ฐ’์€ taintUniqueValue์„ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ค์—ผ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • PIN ์ฝ”๋“œ๋‚˜ ์ „ํ™”๋ฒˆํ˜ธ์™€ ๊ฐ™์ด ๋ณต์žก๋„๊ฐ€ ๋‚ฎ์€ ๊ฐ’์„ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด โ€˜tainUniqueValueโ€™๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ๊ณต๊ฒฉ์ž๊ฐ€ ์š”์ฒญ์˜ ๊ฐ’์„ ์ด์šฉํ•˜์—ฌ ์•”ํ˜ธ์˜ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๊ฐ’์„ ์—ด๊ฑฐํ•˜์—ฌ ์–ด๋–ค ๊ฐ’์ด ์˜ค์—ผ๋˜์—ˆ๋Š”์ง€ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•

ํ† ํฐ์ด ํด๋ผ์ด์–ธํŠธ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์ „๋‹ฌ๋˜์ง€ ์•Š๋„๋ก ๋ฐฉ์ง€ํ•˜๊ธฐ

ํŒจ์Šค์›Œ๋“œ, ์„ธ์…˜ ํ† ํฐ ๋˜๋Š” ๊ธฐํƒ€ ๊ณ ์œ  ๊ฐ’๊ณผ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๊ฐ€ ์‹ค์ˆ˜๋กœ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌ๋˜์ง€ ์•Š๋„๋ก taintUniqueValue ํ•จ์ˆ˜๋Š” ๋ณดํ˜ธ ๋ ˆ์ด์–ด์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ฐ’์ด ์˜ค์—ผ๋˜๋ฉด ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•˜๋ ค๋Š” ์‹œ๋„๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

lifetime ์ธ์ž๋Š” ๊ฐ’์ด ์˜ค์—ผ๋œ ์ƒํƒœ๋กœ ๋‚จ์•„ ์žˆ๋Š” ๊ธฐ๊ฐ„์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์˜ค์—ผ๋œ ์ƒํƒœ๋กœ ๋ฌด๊ธฐํ•œ ์œ ์ง€๋˜์–ด์•ผ ํ•˜๋Š” ๊ฐ’์˜ ๊ฒฝ์šฐ globalThis ๋˜๋Š” process์™€ ๊ฐ™์€ ๊ฐ์ฒด๊ฐ€ lifetime ์ธ์ž๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๋“ค์€ ์•ฑ์ด ์‹คํ–‰๋˜๋Š” ์ „์ฒด ๊ธฐ๊ฐ„์„ ์ˆ˜๋ช…์œผ๋กœ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

import {experimental_taintUniqueValue} from 'react';

experimental_taintUniqueValue(
'ํŒจ์Šค์›Œ๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌํ•˜์ง€ ๋งˆ์„ธ์š”.',
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(
'์„ธ์…˜ ํ† ํฐ์„ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌํ•˜์ง€ ๋งˆ์„ธ์š”.',
user,
user.session.token
);
return user;
}

์ด ์˜ˆ์‹œ์—์„œ user ๊ฐ์ฒด๋Š” lifetime ์ธ์ž ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๊ฐ€ ๊ธ€๋กœ๋ฒŒ ์บ์‹œ์— ์ €์žฅ๋˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์š”์ฒญ์— ์˜ํ•ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์„ธ์…˜ ํ† ํฐ์€ ์˜ค์—ผ๋œ ์ƒํƒœ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

์ฃผ์˜ํ•˜์„ธ์š”!

๋ณด์•ˆ์„ ์˜ค์—ผ์—๋งŒ ์˜์กดํ•˜์ง€ ๋งˆ์„ธ์š”. ๊ฐ’์„ ์˜ค์—ผ์‹œํ‚จ๋‹ค๊ณ  ํ•ด์„œ ๋ชจ๋“  ํŒŒ์ƒ ๊ฐ’์˜ ๋ˆ„์ถœ์ด ๋ฐฉ์ง€๋˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์˜ค์—ผ๋œ ๋ฌธ์ž์—ด์„ ๋Œ€๋ฌธ์ž๋กœ ๋ฐ”๊พธ์–ด ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋งŒ๋“ค๋ฉด ์˜ค์—ผ๋˜์ง€ ์•Š์€ ์ƒˆ๋กœ์šด ๊ฐ’์ด ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

import {experimental_taintUniqueValue} from 'react';

const password = 'correct horse battery staple';

experimental_taintUniqueValue(
'ํŒจ์Šค์›Œ๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌํ•˜์ง€ ๋งˆ์„ธ์š”.',
globalThis,
password
);

const uppercasePassword = password.toUpperCase() // `uppercasePassword`๋Š” ์˜ค์—ผ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ด ์˜ˆ์‹œ์—์„œ๋Š” ์ƒ์ˆ˜ password๊ฐ€ ์˜ค์—ผ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ password์— toUpperCase๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ uppercasePassword๋ผ๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ uppercasePassword๋Š” ์˜ค์—ผ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์˜ค์—ผ๋˜์ง€ ์•Š์€ ์ƒˆ๋กœ์šด ๊ฐ’์ด ๋งŒ๋“ค์–ด์ง€๋Š” ๋‹ค๋ฅธ ์œ ์‚ฌํ•œ ๋ฐฉ๋ฒ•์—๋Š” ์˜ค์—ผ๋œ ๊ฐ’์„ ๋‹ค๋ฅธ ๋ฌธ์ž์—ด๊ณผ ์—ฐ๊ฒฐํ•˜๊ฑฐ๋‚˜, base64๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜, ์ž˜๋ผ๋‚ด๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค์—ผ์€ ๋น„๋ฐ€ ๊ฐ’์„ ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๋‹จ์ˆœํ•œ ์‹ค์ˆ˜๋งŒ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. lifetime ๊ฐ์ฒด ์—†์ด ๋ฆฌ์•กํŠธ ์™ธ๋ถ€์˜ ๊ธ€๋กœ๋ฒŒ ์Šคํ† ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด taintUniqueValue๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹ค์ˆ˜๋Š” ์˜ค์—ผ๋œ ๊ฐ’์„ ์˜ค์—ผ๋˜์ง€ ์•Š์€ ๊ฐ’์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค์—ผ์€ ๋ณดํ˜ธ ๋ ˆ์ด์–ด์ด๋ฉฐ ์•ˆ์ „ํ•œ ์•ฑ์—๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ณดํ˜ธ ๋ ˆ์ด์–ด์™€ ์ž˜ ์„ค๊ณ„๋œ API, ๊ฒฉ๋ฆฌ ํŒจํ„ด์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Deep Dive

๋น„๋ฐ€ ๋ˆ„์ถœ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด์„œ 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 ํ† ํฐ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•ด์„œ๋Š” ์•ˆ ๋˜๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•œ๋‹ค๋ฉด ๋ฐ์ดํ„ฐ ์œ ์ถœ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ๋น„๋ฐ€์€ ์„œ๋ฒ„์˜ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์œ ํ‹ธ๋ฆฌํ‹ฐ์—์„œ๋งŒ ์ž„ํฌํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๋‹จ์ผ ํ—ฌํผ(helper) ํŒŒ์ผ๋กœ ์ถ”์ƒํ™” ๋˜๋Š” ๊ฒƒ์ด ์ด์ƒ์ ์ž…๋‹ˆ๋‹ค. ํ—ฌํผ๋Š” 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(
'API ํ† ํฐ ํŒจ์Šค์›Œ๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌํ•˜์ง€ ๋งˆ์„ธ์š”. ' +
'์„œ๋ฒ„์—์„œ ๋ชจ๋“  fetch๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.'
process,
process.env.API_PASSWORD
);

์ด์ œ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๊ฐ€ ์ด ํŒจ์Šค์›Œ๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜, Server Action์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์— ํŒจ์Šค์›Œ๋“œ๋ฅผ ๋ณด๋‚ด๋ ค๊ณ  ํ•  ๋•Œ๋งˆ๋‹ค taintUniqueValue๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ ์ •์˜ํ•œ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.