본문 바로가기

Front-End: Web/JavaScript

[JavaScript] eval() 함수를 사용하지 마세요! eval() is evil!

반응형

eval()

문자로 표현된 JavaScript 코드를 실행하는 함수.

php, javascript와 같은 스크립트 언어에서 사용할 수 있다.

eval(string)
  • 매개변수
    • string : 자바스크립트 표현식, 명령문, 또는 연속되는 다수의 명령문을 나타내는 문자열. 표현식은 이미 존재하는 객체의 변수나 속성을 포함할 수 있음
  • 반환값
    • 주어진 코드를 평가하여 얻은 값. 값이 없다면 undefined를 반환

(예제)

console.log(eval('2 + 2'));
// expected output: 4

console.log(eval(new String('2 + 2')));
// expected output: 2 + 2

console.log(eval('2 + 2') === eval('4'));
// expected output: true

console.log(eval('2 + 2') === eval(new String('2 + 2')));
// expected output: false

 

특징

1. 전역 객체(window)의 함수 속성이다.

2. 인자가 하나 이상의 js 명령문을 나타낸다면 모두 실행한다.

3. 문자열로 연산식을 구성하면 eval()로 계산할 수 있다.

4. 인자가 문자열이 아니면 인자 그대로를 반환한다.

  • 예로 들어서, String 생성자가 명시된 경우엔 문자열을 계산하는 대신에 String 객체를 반환한다.
eval(new String("2 + 2")); // "2 + 2"를 포함한 String 객체를 반환
eval("2 + 2");             // 4를 반환
  • toString()을 사용하여 해당 제약을 피할 수 있다.
var expression = new String("2 + 2");
eval(expression.toString());            // 4를 반환

 

직접 호출 vs 간접 호출

  • eval()을 직접 호출하지 않고 참조하여 간접적으로 사용하면 지역 범위가 아니라 전역 범위에서 동작한다. (ECMAScript 5부터)
  • eval()로 함수를 선언하면 전역 함수이고, 실행되는 코드는 실행되는 위치의 지역 범위에 접근할 수 없다.
function test() {
  var x = 2, y = 4;
  console.log(eval('x + y'));  // 직접 호출, 지역 범위 사용, 결과값은 6
  var geval = eval; // eval을 전역 범위로 호출하는 것과 같음
  console.log(geval('x + y')); // 간접 호출, 전역 범위 사용, `x`가 정의되지 않았으므로 ReferenceError 발생
  (0, eval)('x + y'); // 다른 방식으로 간접 호출
}

 

eval is evil!

  • eval()은 인자로 받은 코드를 caller의 권한으로 수행하는 위험한 함수다.
  • eval()로 악의적인 영향을 주는 문자열을 실행하, 해당 웹페이지나 확장 프로그램의 권한으로 사용자의 기기에서 악의적인 코드를 수행하게 될 수도 있다. 또한 제 3자 코드가 eval()이 호출된 위치의 스코프를 볼 수 있기 때문에, 이 점을 이용해서 function으로는 할 수 없는 공격이 가능하다.
  • 최신 js 엔진에서 여러 코드 구조를 최적화하는 것과 달리, eval()은 js 인터프리터를 사용해야하기 때문에 다른 대안들보다 느리다.
    • 최신 JS 인터프리터는 자바스크립트를 기계 코드로 변환하는데, 이 말은 변수명의 개념이 완전히 없어진다는 거다. 하지만 eval()을 사용하면 브라우저는 기계 코드에 해당 변수가 있는지 확인하고 값을 대입하기 위해서 길고 무거운 변수명을 검색해야 한다.
    • 또 eval()를 사용하면 자료형 변경 등 변수에 변화가 일어날 수도 있고, 브라우저는 이 때문에 기계 코드를 재작성해야 한다.

대안

  • eval -> window.Function

(ex) eval 사용한 좋지 않은 코드

function looseJsonParse(obj){
    return eval(obj);
}
console.log(looseJsonParse(
   "{a:(4-1), b:function(){}, c:new Date()}"
))

(ex) eval -> window.Function

function looseJsonParse(obj){
    return Function('"use strict";return (' + obj + ')')();
}
console.log(looseJsonParse(
   "{a:(4-1), b:function(){}, c:new Date()}"
))
  • eval() 코드가 훨씬 속도가 느리다. 
  • `c: new Date()` 부분을 보면, Function의 경우에는 이 객체가 전역 범위이기 때문에 브라우저에서는 Date를 같은 이름의 지역 변수가 아닌 window.Date 로 취급할 수 있다. 

 

eval 사용을 지양해야 하는 이유

 

 

 

 


참고 자료

반응형