Hello World

[펌] eval() 함수에 대한 재정의 : eval() is not evil?/ 본문

Javascript/Core

[펌] eval() 함수에 대한 재정의 : eval() is not evil?/

EnterKey 2016. 2. 2. 17:48
반응형

http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

에대한 내용을  참고 하여 정리 해보았다. 


자바스크립트에서 대부분 eval 함수는 계륵 같은 존재 인것 같다. 이 함수에  대해서 "evil"이라고 비방 하고 있는데 .. 과연 이 놈이 evil 일까??

(: 즉 eval함수는 쓰지 않는것이 보안 문제 에 좋다고 알고있으며 본인도 대부분 지양 해서 프로그래밍 중이다. )


이 간단한 함수는  string 으로 자바스크립트 코드를 실행 할수 있게 설계 되었다. 

( 사실 무척이나 유용하다고 할 수 있다. !!) 


하지만  "더글라스 크락포드" 에 의해 "eval() is evil " 이란 구절이 생기면서 대부분의 자바스크립트 개발자는 기피 하고있기도 하다. 


우선 위에서 더글라스 크락포드가 뭐라고 말했는지 살펴보자 

-----------------------------------------------------------------

eval() 함수는 자바스크립트 컴파일러에 접근하는것을 제공 해준다

( Function, setTimeout, setInterval 과 비슷함 )

하지만 대부분의 경우에서 나쁜 코딩에 존재 한다. 

eval 함수의 대부분은 javaScript 의 특징을 오용 하고 있다. 

------------------------------------------------------------------


즉 String 으로 자바스크립트를 작성한다음 eval( string ); 을 하면 

해당 자바스크립트가 실행 되는 아주 고마운(?) api라고 할 수있다. 

하지만 이 eval  이 잘못 사용 되고 있다는 말인데... 


그러면 여기서 의문점이 하나있다. 

" 응 ? 그러면 eval을 잘 사용 하면 사용 해도 된다는 말인가? "


그렇다 해당 블로그를 읽어 보면 eval() 함수는 "악" 이 아니라 단지 오해 일 뿐이라고 한다. 


그렇다면 일단 eval() 함수가 "악" 처럼 보이는 이유에 대해서 알아보자 . 


1. misuse : 오용/남용 

eval 함수를 나쁘다(악을 풀어서 나쁘다라고 적겠다.) 라고 말한 유래에는 대부분 자바스크립트란 언어에 대해서 잘 이해 하지 못한 사람들이 잘못 사용 하는것에 있다고 한다. 

이것은 성능이나 보안 이슈와는 관계가 없다. 

단지 자바스크립트에서 참조를 사용 하고 설계 하는것에 대해 잘 이해 하지 못해서 발생하는 현상이라고 한다. 


예제 코드 1 //잘못된 사용의 예 


function isChecked( optionNumber ) {

return eval ( "forms[0].option" + optionNumber + ".checked:" );

}

var result = isCheced( 1 );




위 코드를 보게 되면 개발자는 forms[0].options1.checked  란 것을 최종적으로 반환 받고 싶어 한하지만 eval()을 사용 하지 않고 이 값을 알수 있는 방법이 있다. 하지만 위와 같이 작성 대부분 eval()을 사용 하지 않고 알수있는 법을 모른다고 보여진다. 

(블로그저자는 실제로 10년차 이상의 개발자 중에 저런 패턴의 코드를 쓰는 경우를 많이 볼수있다고 한다. ) ( 하긴 .. JavaScript 를 대충 사용 하다보면 저런 패턴이 사실 편하긴 할것 같다. )


eval()의 사용은 위 코드에서 적절치 못하며 불필요하다. 즉 위 코드는 나쁘다고 할수있다. 

위 코드는 아래와 같이 쉽게 리팩토링이 가능하다. 


예제 코드 2 // 예제코드 1리팩토링 



 function isChecked( optionNumber ) {

return forms[0]["options" + optionNumber].checked;

}

var result = isChecked(1);



즉 eval()이 사용된 코드중에 대부분은 괄호표기법을 사용해서 대체가 가능하다. 

위의 잘못된 사용이 대부분 크락포드가 잘못된 사용이라고 포함 했던 것들이다. 


2. Debugability : 디버깅 

자 이제 eval()  의을 피해야 하는 좋은 이유중에 하나중 디버깅에 대해서 이야기를 꺼내보자  


지금까지  eval()  코드 안에서 어떤 부분이 잘못되었는지 디버깅 하는것은 불가능해왔다. 

즉 해당 코드는 블랙박스와 같다는 말이다. 

크롬 개발자 툴에서는 eval() 코드를 현재 디버깅 할수있다고 하지만 ( 이부분은 반성해야겠다.. 몰랐다..).. 여전히 그 디버깅 과정이 고통 스럽다고 한다. ( 나중에 예시를 만들어봐야 하나..) 

소스 패널에서 코드가 보이기 전에 한번 코드가 실행 될때까지 기다려야 한다. 

(풀어서 말하자면 코드가 한번 실행 된다음 소스패널에 해당 코드가 보이고나서 디버깅 할수있다는말 ) 


즉 결론적으로 eval()된 코드를 사용 하지 않는것이 소스코드를좀더 단계적으로 쉽게 보일수있다는 말이다.  이것은 eval() 이 evil이란 말이 아니다. 단지 일반적인 개발 과정에서 있는 사소한 문제다 


eval debug problem !== eval is evil 

: 즉 위와 같다는 말이다. :)


3. Performance : 성능 

그다음 문제는.. 좀 중요한 문제라고 할수있다. 


바로 eval()의 성능에 대한 문제다.  


예전 버전의 브라우저에서는 eval()은 중복 Interpretation 패널티를 가졌다. 즉 코드가 한번 interpret 되고, eval() 이 한번더 interpret 가 된다는 말이다. 

eval()이 한번더 interpret될때는 자바스크립트 컴파일링 엔진 없이 되기 때문에 브라우저에서 10배 정도 느려진다 


최근의 자바스크립트 컴파일 엔진에서도 eval()은 여전히 문제를 내포 하고있다. 

대부분의 엔진들은 2가지 방법으로 코드를 실행 하는데. "Fast path ", Slow path " 로 돈다. 

fast path코드는 안정적이고 예측 가능한 코드들이고 빠르게 실행을 위해 컴파일 된다. 하지만 slow path의 경우 예측 하기 힘들기 때문에 컴파일 하기 어렵기 때문에 여전히 interpreter에 의해 실행 된다.

(이부분은 아래의 링크를 봐두면 좋을것 같다. ) 

  1. Know Your Engines by David Mandelin (SlideShare)

즉 eval()부분은 최근의 빠른  자바스크립트 엔진을 사용 하지 못하고 예전 브라우저 속도로 실행 된다는 말이다. ( 다시 말하자면 10 배 느리다. ) 


그리고 또 문제가 있다. eval() 은 YUI Compressor 를 통해 변수 이름을 변경 하는게 불가능 하다. 

eval()은 변수에 바로 접근 할 것이고 이것은 오류로 나타난다.

다른 툴들도 마찬가지다 Closure Compiler나 UglifyJS 에서도 이 문제는 나타난다. 


그래서 eval()을 사용 할때는 성능에 관해서 여전히 심각한 문제들이 잇다. 

하지만... 이렇다고  evil은 아니다. ( 거의 evil일듯...) 


4. Security : 보안 

마지막으로 eval논쟁의 꽃 !! 보안 문제이다. 

이런 논쟁의 화두는 XSS 공격 에 취약하다는 것인데. eval() 이 코드를 오픈 시킬수있다는 것이다. 

표면적으로는 eval()이 정의한 코드가 제멋대로 실행 되는것에대한 우려는 있을만 하다고 보여진다. 

(걱정 하는게 이해가 간다.)

이것은 만약에 사용자 입력을 개발자가 다루고 eval() 에 의해 이게 실행 된다면 위험하다고 할수있다. 

그렇지만 만약에 사용자에 대한 입력을 다루지 않는다면 진짜 위험 할까?


ib/blob/master/src/css/PropertyValuePart.js#L145위 참조한 블로그의 저자는 최근에 eval()을 사용한 CSS Parser의 코드에 대한 complain을 받았다고 한다. ( 링크 : https://github.com/nzakas/parser-lib/blob/master/src/css/PropertyValuePart.js#L145 )


이 부분은 css 에 문자열 토큰을 변환 하기 위해 eval()을 사용 한 것인데  이 경우 어떤 사용 자도 해당 코드를 공격 하고나 문제를 일으킬수 없다고 판단 된다고 한다. 

그렇게 주장하는 이유는 다음과 같다고 한다. 


1. tokenizer 를 통해 전달된 값이 eval()된다. 

2. tokenizer는 이미 해당 string이 유효한 값이라고 판단 한다. 

3. 해당 코드는 커맨드 라인에서 자주 실행 되는 코드다. 

4. 브라우저안에서 실행 될때 해당 코드는 클로저를 통해 보호되고 직접 호출이 불가능하다. 


해당 코드를 직접 본게 아니기 때문에 맞는지 확신은 못하겠지만  어쨌든 보안에 대한 문제는 없다는 것으로 보인다. 


결론적으로 eval()을 사용할때 사용자 입력에 관한  보안 이슈가 있는것은 맞다. 하지만 개발자가 사용자 입력을 eval에서 활용 하지 않고 사용자에 의해 해당 코드가(eval 에서 도는 코드)  변하지 않는다면 보안 위험은 없다고 판단된다. 


(그리고 위 블로그 저자는 보안 이슈에 대한 우려가 있다면 외부 자바스큽트 로딩 코드에 대한 보안을 더 신경 써야 된다고 한다...)


5.Conclusion


결론적으로 eval()을 언제 어디에서나 사용하는것은 적절치 않다. 

그리고 eval()을 사용한 좋은 케이스도 있다!!( 물론, 여기에 code 투명성, 디버깅, 성능에대해서는 간과 하지 말아야 한다.) 

그렇기 때문에 개발자는 eval()을 사용 하는것을 두려워 하지 말아야 한다. 

eval()을 쓰지않는것이 최선이 아니라 eval()을 적절하게 사용 하는것이 최선이라고 말할수있다. 



- 개인적인 결론-

위에 모든 이슈를 다 따지면서 코딩하기는  초급 개발자 또는 중급 개발자도 힘든것 같다. 

가능한 eval()을 안쓰면서 구현 하도록 버릇이 들이고, eval()에 대한 예제를 몇개 만들어 보면서 

정말 필요할때는 같이 프로젝트를 진행 하는 사람들의 동의를 얻어서 code에 추가하는게 좋을것같다. 

참고로 JSLint에서는 무조건 eval()이 검출 되니 .. JSHint 를 사용하는것이 조금더 바람직(?) 할 것 같다. 


출처: http://t.kazikai.net/115

반응형
Comments