JavaScript์—์„œ eval()์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•

JavaScript์—์„œ eval()์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•

D
dongAuthor
5 min read

JavaScript์˜ eval()์ด ์œ„ํ—˜ํ•œ ์ด์œ ์™€ new Function()์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ๋Œ€์ฒดํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ์•Œ์•„๋ณด์„ธ์š”. ๋ณด์•ˆ๊ณผ ์„ฑ๋Šฅ์„ ๋ชจ๋‘ ์žก๋Š” ํŒ!

JavaScript๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋ฉด ๋ฌธ์ž์—ด๋กœ ๋œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿด ๋•Œ ๊ฐ€์žฅ ๋จผ์ € ๋– ์˜ค๋ฅด๋Š” ๊ฒƒ์ด eval() ํ•จ์ˆ˜์ฃ . ํ•˜์ง€๋งŒ eval()์€ ๋ณด์•ˆ ์ทจ์•ฝ์ ๊ณผ ์„ฑ๋Šฅ ๋ฌธ์ œ๋กœ ์•…๋ช…์ด ๋†’์Šต๋‹ˆ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” eval()์˜ ์œ„ํ—˜์„ฑ์„ ์‚ดํŽด๋ณด๊ณ , ๋” ์•ˆ์ „ํ•œ ๋Œ€์•ˆ์ธ new Function()์„ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

eval()์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

MDN ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด, eval()์€ ๋ฌธ์ž์—ด๋กœ ํ‘œํ˜„๋œ JavaScript ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์ž‘๋™ ๋ฐฉ์‹์„ ์‚ดํŽด๋ณผ๊นŒ์š”?

let a = 3;
let b = 5;
eval('a += ' + b + ' + 2');
console.log(a); // 10

์œ„ ์ฝ”๋“œ์—์„œ eval()์€ ๋ฌธ์ž์—ด 'a += 5 + 2'๋ฅผ ์‹ค์ œ JavaScript ์ฝ”๋“œ๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์–ผํ• ๋ณด๋ฉด ํŽธ๋ฆฌํ•ด ๋ณด์ด์ง€๋งŒ, ์ด ๋‹จ์ˆœํ•จ ๋’ค์—๋Š” ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๋“ค์ด ์ˆจ์–ด ์žˆ์–ด์š”.

eval()์˜ ๋ณด์•ˆ ์œ„ํ—˜์„ฑ

eval()์€ caller์˜ ๊ถŒํ•œ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ ๋ฌด์Šจ ์˜๋ฏธ์ผ๊นŒ์š”? ๋งŒ์•ฝ ์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ฐ’์„ eval()๋กœ ์‹คํ–‰ํ•œ๋‹ค๋ฉด, ์•…์˜์ ์ธ ์ฝ”๋“œ๊ฐ€ ๊ทธ๋Œ€๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.

var userContent = getUserInput(); // ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ๋ฐ›์€ ๊ฐ’
eval(userContent); // ์œ„ํ—˜!

ํ•ด์ปค๊ฐ€ "window.location = 'http://malicious-site.com'"์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ์‚ฌ์šฉ์ž๋Š” ์•…์„ฑ ์‚ฌ์ดํŠธ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๊ฑฐ๋‚˜, ๋” ์‹ฌ๊ฐํ•œ ๊ฒฝ์šฐ ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ํƒˆ์ทจ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ eval()์€ ํ˜ธ์ถœ๋œ ์Šค์ฝ”ํ”„(scope)์— ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๋Š” ๋กœ์ปฌ ๋ณ€์ˆ˜๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค:

function MyFunc() {
  let secretToken = "abc123";
  eval('console.log(secretToken); secretToken = "hacked";');
  console.log(secretToken); // "hacked"
}

eval()์˜ ์„ฑ๋Šฅ ๋ฌธ์ œ

eval()์€ JavaScript ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๋Œ€์•ˆ๋“ค๋ณด๋‹ค ๋А๋ฆฝ๋‹ˆ๋‹ค. ํ˜„๋Œ€ JavaScript ์—”์ง„๋“ค์€ ์ฝ”๋“œ๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š”๋ฐ, eval()์€ ์ด๋Ÿฌํ•œ ์ตœ์ ํ™”๋ฅผ ๋ฐฉํ•ดํ•ฉ๋‹ˆ๋‹ค. ์—”์ง„์ด ์–ด๋–ค ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋ ์ง€ ๋ฏธ๋ฆฌ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

new Function()์œผ๋กœ ๋” ์•ˆ์ „ํ•˜๊ฒŒ

new Function()์€ eval()๊ณผ ๋น„์Šทํ•˜๊ฒŒ ๋ฌธ์ž์—ด๋กœ๋ถ€ํ„ฐ ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜์ง€๋งŒ, ํ›จ์”ฌ ๋” ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์‚ดํŽด๋ณผ๊นŒ์š”?

const add = new Function('a', 'b', 'return a + b');
console.log(add(2, 3)); // 5

๋ฌธ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

let func = new Function([arg1, arg2, ...argN], functionBody);

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ ์€ new Function()์œผ๋กœ ์ƒ์„ฑ๋œ ํ•จ์ˆ˜๋Š” ํ•ญ์ƒ ์ „์—ญ ์Šค์ฝ”ํ”„์—์„œ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋กœ์ปฌ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์–ด์š”:

function MyFunc() {
  let b = 123;
  new Function('console.log(b);')(); // ReferenceError: b is not defined
}

์ด๋Ÿฐ ์ œ์•ฝ์ด ์˜คํžˆ๋ ค ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•ฉ๋‹ˆ๋‹ค. ์•…์˜์ ์ธ ์ฝ”๋“œ๊ฐ€ ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ ๋ฏผ๊ฐํ•œ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์„ ์›์ฒœ์ ์œผ๋กœ ์ฐจ๋‹จํ•˜๋Š” ๊ฑฐ์ฃ .

eval()๊ณผ new Function() ๋น„๊ตํ•˜๊ธฐ

๋‘ ๋ฐฉ์‹์˜ ํ•ต์‹ฌ ์ฐจ์ด์ ์„ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ์š”.

์‹คํ–‰ ์ปจํ…์ŠคํŠธ์™€ ์Šค์ฝ”ํ”„

eval()์€ ํ˜„์žฌ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ์—์„œ ์ฝ”๋“œ๋ฅผ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค:

function testEval() {
  let x = 10;
  eval('console.log(x); x = 20;');
  console.log(x); // 20 - ๋ณ€์ˆ˜๊ฐ€ ์ˆ˜์ •๋จ
}
testEval();

๋ฐ˜๋ฉด new Function()์€ ์ „์—ญ ์ปจํ…์ŠคํŠธ์—์„œ๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค:

function testFunction() {
  let x = 10;
  const func = new Function('console.log(typeof x);'); // "undefined"
  func();
  console.log(x); // 10 - ๋ณ€์ˆ˜๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณดํ˜ธ๋จ
}
testFunction();

๋ณด์•ˆ์„ฑ

new Function()์˜ ์ œํ•œ๋œ ์Šค์ฝ”ํ”„ ์ ‘๊ทผ์€ ๋ณด์•ˆ์ƒ ํฐ ์žฅ์ ์ž…๋‹ˆ๋‹ค. ๋กœ์ปฌ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ์•…์˜์ ์ธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋”๋ผ๋„ ํ”ผํ•ด ๋ฒ”์œ„๊ฐ€ ์ œํ•œ์ ์ด์—์š”.

์‹ค์ „ ์˜ˆ์ œ๋กœ ๋ฐฐ์šฐ๊ธฐ

์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ eval()์„ new Function()์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

๊ฐ„๋‹จํ•œ ์ˆ˜์‹ ๊ณ„์‚ฐ

// eval() ์‚ฌ์šฉ (๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ)
const result1 = eval('2 + 3 * 4');

// new Function() ์‚ฌ์šฉ (๊ถŒ์žฅ)
const calculate = new Function('return 2 + 3 * 4');
const result2 = calculate();

๋™์  ํ•จ์ˆ˜ ์ƒ์„ฑ

// ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ•จ์ˆ˜ ๋ณธ๋ฌธ์œผ๋กœ ํ•จ์ˆ˜ ์ƒ์„ฑ
const functionBody = 'return x * 2';
const double = new Function('x', functionBody);
console.log(double(5)); // 10

์™ธ๋ถ€ ๋ณ€์ˆ˜ ์•ˆ์ „ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜๊ธฐ

์ „์—ญ ๋ณ€์ˆ˜๋Š” new Function()์—์„œ๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ๋” ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•์€ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค:

const multiplier = 3;

// ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ช…์‹œ์  ์ „๋‹ฌ
const multiply = new Function('x', 'multiplier', 'return x * multiplier');
console.log(multiply(5, multiplier)); // 15

JSON ํŒŒ์‹ฑ ๋Œ€์•ˆ

์—„๊ฒฉํ•œ JSON์ด ์•„๋‹Œ JavaScript ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์„ ํŒŒ์‹ฑํ•  ๋•Œ๋„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”:

function looseJsonParse(obj) {
  return Function('"use strict";return (' + obj + ")")();
}

const result = looseJsonParse("{a:(4-1), b:function(){}, c:new Date()}");
console.log(result.a); // 3

์–ธ์ œ new Function()์„ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ?

new Function()์ด ์œ ์šฉํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋“ค์„ ์‚ดํŽด๋ณผ๊ฒŒ์š”:

๋™์  ์ฝ”๋“œ ์ƒ์„ฑ

์„ค์ • ํŒŒ์ผ์ด๋‚˜ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž ์ •์˜ ํ•„ํ„ฐ๋‚˜ ์ •๋ ฌ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ๋•Œ์ฃ .

์ƒŒ๋“œ๋ฐ•์Šค ํ™˜๊ฒฝ

์ „์—ญ ์Šค์ฝ”ํ”„์—์„œ๋งŒ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์—, ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ์ด๋‚˜ ์‚ฌ์šฉ์ž ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ๋งŒ๋“ค ๋•Œ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ

๋ฐ˜๋ณต์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ๋ผ๋ฉด, ํ•œ ๋ฒˆ new Function()์œผ๋กœ ์ปดํŒŒ์ผํ•œ ํ›„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด eval()์„ ๋งค๋ฒˆ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ๊ณผ ํ•œ๊ณ„

new Function()๋„ ์™„๋ฒฝํ•œ ํ•ด๊ฒฐ์ฑ…์€ ์•„๋‹™๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ๋ฌธ์ž์—ด๋กœ๋ถ€ํ„ฐ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ, ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ž…๋ ฅ์€ ์ฒ ์ €ํžˆ ๊ฒ€์ฆํ•ด์•ผ ํ•ด์š”.

๋˜ํ•œ ์ผ๋ถ€ ์—ฃ์ง€ ์ผ€์ด์Šค์—์„œ๋Š” eval()์ด๋‚˜ new Function() ๋ชจ๋‘ ์ ํ•ฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋Œ€์•ˆ์„ ๋จผ์ € ๊ณ ๋ คํ•ด๋ณด์„ธ์š”:

๊ฐ์ฒด ์†์„ฑ ์ ‘๊ทผ ์‹œ:

// eval() ์‚ฌ์šฉ (๋‚˜์จ)
const propName = 'username';
const value = eval('user.' + propName);

// ๋ธŒ๋ผ์ผ“ ํ‘œ๊ธฐ๋ฒ• ์‚ฌ์šฉ (์ข‹์Œ)
const value = user[propName];

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋“ฑ๋ก ์‹œ:

// ์ธ๋ผ์ธ ๋ฌธ์ž์—ด (๋‚˜์จ)
element.setAttribute("onclick", "handleClick()");

// ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ (์ข‹์Œ)
element.addEventListener("click", handleClick);

ํƒ€์ด๋จธ ํ•จ์ˆ˜ ์‚ฌ์šฉ ์‹œ:

// ๋ฌธ์ž์—ด ์ฝ”๋“œ (๋‚˜์จ)
setTimeout("console.log('Hello')", 1000);

// ํ•จ์ˆ˜ ์ „๋‹ฌ (์ข‹์Œ)
setTimeout(() => console.log('Hello'), 1000);

๋” ์•ˆ์ „ํ•œ ์ฝ”๋“œ๋ฅผ ํ–ฅํ•ด

eval()์€ ํŽธ๋ฆฌํ•ด ๋ณด์ด์ง€๋งŒ, ๋ณด์•ˆ๊ณผ ์„ฑ๋Šฅ ์ธก๋ฉด์—์„œ ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. new Function()์€ ์ „์—ญ ์Šค์ฝ”ํ”„ ์ œํ•œ์„ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ์œ„ํ—˜์„ ํฌ๊ฒŒ ์ค„์—ฌ์ฃผ๋Š” ๋” ๋‚˜์€ ๋Œ€์•ˆ์ด์—์š”.

๋ฌผ๋ก  ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋™์  ์ฝ”๋“œ ์‹คํ–‰ ์ž์ฒด๋ฅผ ํ”ผํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ถˆ๊ฐ€ํ”ผํ•œ ์ƒํ™ฉ์ด๋ผ๋ฉด, new Function()์„ ์„ ํƒํ•˜๋˜ ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ์„ ์ฒ ์ €ํžˆ ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์„ธ์š”.

๋ณด์•ˆ์€ ํƒ€ํ˜‘ํ•  ์ˆ˜ ์—†๋Š” ์˜์—ญ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ ํ•œ ์ค„์ด ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์•ˆ์ „์„ ์ขŒ์šฐํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ํ•ญ์ƒ ๊ธฐ์–ตํ•˜๋ฉด์„œ ๊ฐœ๋ฐœํ•˜์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค :)

JavaScript์—์„œ eval()์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•