π eval() λλ new Function()μΌλ‘ λμ μ½λ μ€ννκΈ°: 보μκ³Ό μ±λ₯μ 무λ€
Summary
eval()
λ° new Function()
μ λ¬Έμμ΄μ μ½λλ‘ μ€ννμ¬ μΉ μ ν리μΌμ΄μ
μ μ¬κ°ν 보μ μ·¨μ½μ (XSS)μ μΌκΈ°νκ³ , μ±λ₯ μ ν λ° λλ²κΉ
μ μ΄λ €μμ μ΄λν©λλ€. λμ JSON.parse()
, ν
νλ¦Ώ μμ§, λλ ν¨μ μ½λ°±κ³Ό κ°μ μμ νκ³ ν¨μ¨μ μΈ λμμ μ¬μ©νμ¬ λ³΄μκ³Ό μ½λ νμ§μ ν보ν΄μΌ ν©λλ€.
Why Wrong?
1. μ¬κ°ν 보μ μ·¨μ½μ (XSS)
eval()
ν¨μλ μΈμλ‘ μ λ¬λ λ¬Έμμ΄μ JavaScript μ½λλ‘ ν΄μνκ³ μ€νν©λλ€. μ΄λ μ¬μ©μ μ
λ ₯κ³Ό κ°μ μ λ’°ν μ μλ μμ€μ λ¬Έμμ΄μ eval()
μ μ λ¬ν κ²½μ°, 곡격μκ° μμμ μ½λλ₯Ό μΉ μ ν리μΌμ΄μ
λ΄μμ μ€νν μ μλ XSS(Cross-Site Scripting) μ·¨μ½μ μΌλ‘ μ΄μ΄μ§ μ μμ΅λλ€. μλ₯Ό λ€μ΄, μ
μ± μ€ν¬λ¦½νΈλ₯Ό μ£Όμ
νμ¬ μ¬μ©μ μΈμ
μ νμ·¨νκ±°λ λ―Όκ°ν μ 보λ₯Ό μ μΆν μ μμ΅λλ€.
new Function()
μμ±μ μμ μ μ¬ν 보μ μνμ λ΄ν¬ν©λλ€. λ¬Έμμ΄λ‘ ν¨μ λ³Έλ¬Έμ μ μνκΈ° λλ¬Έμ, μ λ’°ν μ μλ μμ€μ λ¬Έμμ΄μ μ¬μ©νλ©΄ eval()
κ³Ό λμΌν 곡격 벑ν°κ° λ°μν©λλ€.
2. μ±λ₯ μ ν λ° μ΅μ ν λ°©ν΄
JavaScript μμ§μ μ½λλ₯Ό 미리 νμ±νκ³ μ΅μ ννμ¬ μ€ν μλλ₯Ό λμ
λλ€. νμ§λ§ eval()
μ΄λ new Function()
μΌλ‘ λμ μΌλ‘ μμ±λ μ½λλ λ°νμμ νμ± λ° μ»΄νμΌ κ³Όμ μ κ±°μ³μΌ νλ―λ‘, 미리 μ΅μ νλ μ½λλ³΄λ€ ν¨μ¬ λλ¦¬κ² μ€νλ μ μμ΅λλ€. λν, eval()
μ νΈμΆλλ μ€μ½νλ₯Ό λ³κ²½ν μ μλ νΉμ± λλ¬Έμ, JIT(Just-In-Time) μ»΄νμΌλ¬κ° ν΄λΉ μ€μ½νμ λ³μλ ν¨μλ₯Ό μ΅μ ννλ κ²μ λ°©ν΄νμ¬ μ 체 μ ν리μΌμ΄μ
μ μ±λ₯μλ μ
μν₯μ λ―ΈμΉ μ μμ΅λλ€.
3. λλ²κΉ μ μ΄λ €μ
λμ μΌλ‘ μμ±λ μ½λλ μμ€ λ§΅(Source Map) μ§μμ΄ μ΄λ ΅κ±°λ λΆκ°λ₯νμ¬, μμμΉ λͺ»ν μ€λ₯κ° λ°μνμ λ λλ²κΉ
νκΈ°κ° λ§€μ° μ΄λ ΅μ΅λλ€. μ€ν νΈλ μ΄μ€μμ eval code
λλ anonymous
λ±μΌλ‘ νμλμ΄ λ¬Έμ μ κ·Όμμ νμ
νκΈ° νλ€μ΄μ§λλ€.
4. CSP(Content Security Policy) μλ°
λλΆλΆμ νλ μΉ μ ν리μΌμ΄μ
μ XSS 곡격μ μννκΈ° μν΄ μ격ν CSPλ₯Ό μ¬μ©ν©λλ€. eval()
μ΄λ new Function()
κ°μ λμ μ½λ μ€ν λ©μλλ CSPμ unsafe-eval
μ§μμ΄λ₯Ό νμλ‘ νλ©°, μ΄λ 보μ μ μ±
μ μ½νμν΅λλ€. κ°λ ₯ν CSPλ μ΄λ¬ν λμ μ½λ μ€νμ κΈ°λ³Έμ μΌλ‘ μ°¨λ¨νμ¬ μ ν리μΌμ΄μ
μ΄ μλνμ§ μκ² λ§λ€ μ μμ΅λλ€.
How to Fix?
1. JSON.parse()
νμ© (JSON λ°μ΄ν° μ²λ¦¬ μ)
eval()
μ κ°μ₯ νν μ€μ© μ¬λ‘ μ€ νλλ JSON λ¬Έμμ΄μ JavaScript κ°μ²΄λ‘ λ³ννλ κ²μ
λλ€. μ΄ κ²½μ° λ°λμ JSON.parse()
λ₯Ό μ¬μ©ν΄μΌ ν©λλ€. JSON.parse()
λ JSON νμ€μ λ§λ λ¬Έμμ΄λ§ μμ νκ² νμ±νλ©°, JavaScript μ½λλ‘ ν΄μνμ§ μμ 보μ μνμ΄ μμ΅λλ€.
2. ν νλ¦Ώ μμ§ λλ νλ μμν¬μ λ λλ§ κΈ°λ₯ νμ© (λμ UI/HTML μμ± μ)
λμ μΌλ‘ UIλ₯Ό μμ±ν΄μΌ νλ€λ©΄, Reactμ JSX, Vueμ ν νλ¦Ώ, λλ Handlebars, Pugμ κ°μ μμ ν ν νλ¦Ώ μμ§μ μ¬μ©νμΈμ. μ΄λ€μ μ¬μ©μ μ λ ₯μ μλμΌλ‘ μ΄μ€μΌμ΄ν μ²λ¦¬νμ¬ XSS 곡격μ λ°©μ§νκ³ , μ½λμ λ°μ΄ν°μ λΆλ¦¬λ₯Ό λͺ νν νμ¬ μ μ§λ³΄μμ±μ λμ λλ€.
3. ν¨μ λ§€κ°λ³μ λλ μ€μ κ°μ²΄ μ¬μ© (λμ λ‘μ§ κ΅¬ν μ)
λμ μΈ λμμ΄ νμνλ€λ©΄, λ¬Έμμ΄μ μ½λλ‘ μ€ννλ λμ ν¨μλ₯Ό λ§€κ°λ³μλ‘ μ λ¬νκ±°λ, μ€μ κ°μ²΄λ₯Ό ν΅ν΄ λμμ μ μ΄νλ λ°©μμ μ¬μ©νμΈμ. μ΄λ ν¨μ¬ μμ νκ³ λλ²κΉ νκΈ° μ¬μ΄ μ κ·Ό λ°©μμ λλ€.
4. μΉ μ΄μ λΈλ¦¬ (WebAssembly) κ³ λ € (κ³ μ±λ₯ κ³μ° λ‘μ§)
λ§€μ° λ³΅μ‘νκ±°λ μ±λ₯μ΄ μ€μν κ³μ° λ‘μ§μ λμ μΌλ‘ λ‘λνκ³ μ€νν΄μΌ νλ€λ©΄, μΉ μ΄μ λΈλ¦¬λ₯Ό κ³ λ €ν μ μμ΅λλ€. μΉ μ΄μ λΈλ¦¬λ JavaScriptμλ λ€λ₯Έ μ΄μ§ νμμΌλ‘, μλλ°μ€ νκ²½μμ μ€νλμ΄ λ³΄μμ±μ΄ λκ³ μ±λ₯λ λ°μ΄λ©λλ€.
ν΅μ¬μ 'μ½λ μ€ν'μ΄ μλ 'λ°μ΄ν° μ²λ¦¬' λλ 'ν¨μ μ λ¬'λ‘ λ¬Έμ λ₯Ό ν΄κ²°νλ κ²μ λλ€. μ΄λ μ½λμ μμ μ±, 보μμ±, κ·Έλ¦¬κ³ μ μ§λ³΄μμ±μ ν¬κ² ν₯μμν΅λλ€.
Before Code (Bad)
// case 1: JSON λ¬Έμμ΄μ κ°μ²΄λ‘ λ³ν
const unsafeJsonString = "({ name: 'Alice', age: 30 })"; // μ€μ λ‘λ μ¬μ©μ μ
λ ₯ λ± μΈλΆμμ μ¬ μ μμ
const user = eval(unsafeJsonString); // π¨ 보μ μ·¨μ½μ : XSS μν!
console.log(user.name);
// case 2: λμ μΌλ‘ ν¨μ μμ±
const operation = 'a + b';
const calculate = new Function('a', 'b', `return ${operation};`); // π¨ 보μ μ·¨μ½μ λ° μ±λ₯ μ ν
console.log(calculate(5, 3));
// case 3: setTimeout/setIntervalμ λ¬Έμμ΄ μ λ¬ (evalκ³Ό μ μ¬)
const maliciousCode = "alert('μΈμ
νμ·¨λ¨!');";
setTimeout(maliciousCode, 1000); // π¨ evalκ³Ό λμΌν 보μ μν!
After Code (Good)
// case 1: JSON λ¬Έμμ΄μ κ°μ²΄λ‘ λ³ν
// μ¬μ©μ μ
λ ₯μ΄ JSON ννλ‘ μ¬ κ²½μ°, λ°λμ JSON.parse() μ¬μ©
const safeJsonString = '{"name": "Bob", "age": 25}';
try {
const user = JSON.parse(safeJsonString); // β¨ μμ νκ³ ν¨μ¨μ μΈ λ°©λ²
console.log(user.name);
} catch (e) {
console.error('JSON νμ± μλ¬:', e);
}
// case 2: λμ μΌλ‘ ν¨μ μμ± (λ°μ΄ν°/ν¨μ μ λ¬ λ°©μ)
const operationFunction = (a, b) => a + b; // 미리 μ μλ ν¨μ μ¬μ©
console.log(operationFunction(5, 3));
// λλ μ€μ κ°μ²΄λ₯Ό ν΅ν΄ λμ λμ μ μ΄
const config = {
operation: 'add',
perform: (a, b) => a + b
};
console.log(config.perform(5, 3));
// case 3: setTimeout/setIntervalμ ν¨μ μ λ¬
const secureAction = () => {
console.log('μμ νκ² μ€νλμμ΅λλ€.');
};
setTimeout(secureAction, 1000); // β¨ ν¨μ μ°Έμ‘°λ₯Ό μ§μ μ λ¬