experimental_taintUniqueValue
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
์ธ์ ์ญํ ์ ํฉ๋๋ค. ์ด ๊ฐ์ฒด๊ฐ ๊ธ๋ก๋ฒ ์บ์์ ์ ์ฅ๋๊ฑฐ๋ ๋ค๋ฅธ ์์ฒญ์ ์ํด ์ ๊ทผํ ์ ์๋ค๋ฉด ์ธ์
ํ ํฐ์ ์ค์ผ๋ ์ํ๋ก ์ ์ง๋ฉ๋๋ค.
Deep Dive
๋ฐ์ดํฐ๋ฒ ์ด์ค ํจ์ค์๋์ ๊ฐ์ ๊ฐ์ธ ํค ๋๋ ํจ์ค์๋์ ์ ๊ทผํ ์ ์๋ ์๋ฒ ์ปดํฌ๋ํธ ํ๊ฒฝ์ ์คํํ๋ ๊ฒฝ์ฐ ๊ฐ์ธ ํค๋ ํจ์ค์๋๋ฅผ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ์ ๋ฌํ์ง ์๋๋ก ์ฃผ์ํด์ผ ํฉ๋๋ค.
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
๋ฅผ ํธ์ถํ์ ๋ ์ ์ํ ๋ฉ์์ง์ ํจ๊ป ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.