문제

eval 함수는 코드를 동적으로 생성하는 강력하고 쉬운 방법입니다. 그렇다면 주의할 점은 무엇입니까?

도움이 되었습니까?

해결책

  1. 부적절한 사용 평가 주입 공격에 대한 코드를 열어줍니다

  2. 디버깅 더 어려울 수 있습니다 (라인 번호 없음 등)

  3. 평가된 코드가 느리게 실행됩니다(평가된 코드를 컴파일/캐시할 기회가 없음).

편집하다:@Jeff Walden이 댓글에서 지적했듯이 #3은 2008년보다 오늘날 사실이 덜 사실입니다.그러나 컴파일된 스크립트의 일부 캐싱이 발생할 수 있지만 이는 수정 없이 반복적으로 평가되는 스크립트에만 제한됩니다.더 가능성 있는 시나리오는 매번 약간의 수정을 거쳐 캐시할 수 없는 스크립트를 평가하는 것입니다.일부 평가된 코드가 더 느리게 실행된다고 가정해 보겠습니다.

다른 팁

평가가 항상 악한 것은 아닙니다.아주 딱 맞는 경우도 있습니다.

그러나 eval은 현재 그리고 역사적으로 자신이 무엇을 하고 있는지 모르는 사람들에 의해 과도하게 사용되고 있습니다.여기에는 불행하게도 JavaScript 튜토리얼을 작성하는 사람들도 포함되며 어떤 경우에는 실제로 보안에 영향을 미치거나 단순한 버그가 발생할 수 있습니다.따라서 평가에 대해 물음표를 던질 수 있는 일이 많을수록 좋습니다.eval을 사용할 때마다 현재 수행 중인 작업이 제대로 작동하는지 확인해야 합니다. 더 나은, 더 안전하고 깨끗한 방법으로 작업을 수행할 가능성이 있기 때문입니다.

너무 일반적인 예를 들어, 변수 'potato'에 저장된 ID를 사용하여 요소의 색상을 설정하려면 다음을 수행하십시오.

eval('document.' + potato + '.style.color = "red"');

위 종류의 코드 작성자가 JavaScript 객체의 기본 작동 방식에 대한 단서를 갖고 있었다면 리터럴 점 이름 대신 대괄호를 사용하여 평가의 필요성을 제거할 수 있다는 것을 깨달았을 것입니다.

document[potato].style.color = 'red';

...이것은 읽기가 훨씬 쉬울 뿐만 아니라 잠재적인 버그도 적습니다.

(하지만 자신이 하고 있는 일을 /정말로/ 아는 누군가는 다음과 같이 말할 것입니다.

document.getElementById(potato).style.color = 'red';

이는 문서 객체에서 바로 DOM 요소에 액세스하는 낡은 트릭보다 더 안정적입니다.)

나는 이것이 문자열에서 어떤 JavaScript 함수라도 실행할 수 있기 때문이라고 생각합니다.이를 사용하면 사람들이 애플리케이션에 악성 코드를 더 쉽게 삽입할 수 있습니다.

두 가지 점이 떠오릅니다.

  1. 보안(그러나 평가할 문자열을 직접 생성하는 한 이는 문제가 되지 않을 수 있습니다)

  2. 성능:실행될 코드를 알 수 없을 때까지는 최적화할 수 없습니다.(자바스크립트와 성능에 대해서는 확실히 스티브 예게(Steve Yegge)의 프레젠테이션)

사용자 입력을 eval()에 전달하는 것은 보안 위험이 있지만 eval()을 호출할 때마다 JavaScript 인터프리터의 새 인스턴스가 생성됩니다.이는 리소스를 많이 차지할 수 있습니다.

일반적으로 평가 사용자 입력을 전달하는 경우에만 문제가 됩니다.

주로 유지 관리 및 디버깅이 훨씬 어렵습니다.그것은 마치 goto.이를 사용할 수는 있지만 나중에 변경해야 할 수도 있는 사람들이 문제를 발견하기 더 어렵게 만들고 더 어렵게 만듭니다.

한 가지 명심해야 할 점은 제한된 환경에서 코드를 실행하기 위해 eval()을 자주 사용할 수 있다는 것입니다. 특정 JavaScript 기능을 차단하는 소셜 네트워킹 사이트는 때때로 해당 기능을 eval 블록에서 분리하여 속일 수 있습니다.

eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');

따라서 허용되지 않을 수 있는 일부 JavaScript 코드를 실행하려는 경우(내 공간, 보고 있어요...) 그러면 eval()이 유용한 트릭이 될 수 있습니다.

그러나 위에서 언급한 모든 이유로 인해 완전한 제어권을 갖고 있는 자신의 코드에 이를 사용해서는 안 됩니다. 단지 필요하지 않을 뿐이며 '까다로운 JavaScript 해킹' 선반에 두는 것이 더 나을 뿐입니다.

eval()에 동적 콘텐츠(cgi 또는 입력을 통해)를 허용하지 않는 한 이는 페이지의 다른 모든 JavaScript만큼 안전하고 견고합니다.

나머지 답변과 함께 평가 문은 고급 최소화를 가질 수 없다고 생각합니다.

이는 보안 위험이 있을 수 있고 실행 범위가 다르며 코드 실행을 위해 완전히 새로운 스크립팅 환경을 생성하므로 매우 비효율적입니다.자세한 내용은 여기를 참조하세요. 평가.

하지만 꽤 유용하며 적당히 사용하면 좋은 기능을 많이 추가할 수 있습니다.

평가 중인 코드가 신뢰할 수 있는 소스(일반적으로 자신의 응용 프로그램)에서 나온 것이라고 100% 확신하지 않는 한 이는 시스템을 크로스 사이트 스크립팅 공격에 노출시키는 확실한 방법입니다.

이 토론이 오래되었다는 것을 알고 있지만 정말 마음에 듭니다. 이것 Google이 접근하여 그 느낌을 다른 사람들과 공유하고 싶었습니다. ;)

또 다른 것은 더 나은 것이 더 좋을수록 이해하려고 노력하고 마침내 누군가가 그렇게 말했기 때문에 무언가가 좋거나 나쁘다고 믿지 않는다는 것입니다. :) 이것은 매우 영감을줍니다. 동영상 그것은 제가 스스로 더 많이 생각하는 데 도움이 되었습니다 :) 좋은 습관은 좋지만, 무심코 사용하지 마세요 :)

어떤 맥락에서 사용하고 있는지 안다면 반드시 그렇게 나쁜 것은 아닙니다.

귀하의 응용 프로그램이 다음을 사용하는 경우 eval() 반환된 일부 JSON에서 객체를 생성하려면 XMLHttp요청 신뢰할 수 있는 서버 측 코드로 생성된 자신의 사이트에 연결하는 것은 아마도 문제가 아닐 것입니다.

신뢰할 수 없는 클라이언트측 JavaScript 코드는 어쨌든 그렇게 많은 일을 할 수 없습니다.당신이 실행중인 것을 제공 eval() 합리적인 출처에서 나온 것입니다. 괜찮습니다.

보안에 대한 신뢰 수준이 크게 감소합니다.

사용자가 일부 논리 함수를 입력하고 AND와 OR을 평가하도록 하려면 JavaScript 평가 함수가 완벽합니다.두 개의 문자열을 받아들일 수 있고 eval(uate) string1 === string2, 등.

코드에서 eval() 사용을 발견했다면 "eval()은 사악하다"는 주문을 기억하세요.

이 함수는 임의의 문자열을 사용하여 JavaScript 코드로 실행합니다.문제의 코드가 미리 알려지면 (런타임에 결정되지 않음) eval ()를 사용할 이유가 없습니다.런타임에 코드가 동적으로 생성되면 Eval ()없이 목표를 달성하는 더 좋은 방법이 종종 있습니다.예를 들어, 동적 특성에 액세스하기 위해 사각형 브래킷 표기법을 사용하는 것만으로는 더 쉽고 간단합니다.

// antipattern
var property = "name";
alert(eval("obj." + property));

// preferred
var property = "name";
alert(obj[property]);

사용 eval() 또한 변조 된 코드 (예 : 네트워크에서 나오는)를 실행하고 있기 때문에 보안 영향도 있습니다.이는 Ajax 요청의 JSON 응답을 처리할 때 흔히 나타나는 안티패턴입니다.이 경우 브라우저의 내장 방법을 사용하여 JSON 응답을 구문 분석하여 안전하고 유효한 지 확인하는 것이 좋습니다.지원하지 않는 브라우저의 경우 JSON.parse() 기본적으로 json.org에서 라이브러리를 사용할 수 있습니다.

문자열을 다음에 전달한다는 것을 기억하는 것도 중요합니다. setInterval(), setTimeout(), 그리고 Function() 생성자는 대부분 다음을 사용하는 것과 유사합니다. eval() 그러므로 피해야합니다.

무대 뒤에서 JavaScript는 여전히 전달한 문자열을 프로그래밍 코드로 평가하고 실행해야합니다.

// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

// preferred
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);

새 기능 () 생성자를 사용하는 것은 eval ()과 유사하며주의해서 접근해야합니다.이는 강력한 구조일 수 있지만 종종 오용됩니다.당신이 절대적으로 사용해야한다면 eval(), 대신 new Function() 사용을 고려할 수 있습니다.

New Function ()에서 평가 된 코드가 로컬 기능 범위에서 실행되므로 평가중인 코드의 Var로 정의 된 변수는 자동으로 글로벌이되지 않기 때문에 잠재적 인 이점이 적습니다.

자동 전역을 방지하는 또 다른 방법은 다음을 래핑하는 것입니다.eval() 즉각적인 기능을 호출합니다.

사용자가 제출한 코드를 실행하는 경우 발생할 수 있는 보안 문제 외에도 대부분의 경우 코드가 실행될 때마다 코드를 다시 구문 분석하지 않는 더 나은 방법이 있습니다.익명 함수 또는 객체 속성은 대부분의 eval 사용을 대체할 수 있으며 훨씬 안전하고 빠릅니다.

차세대 브라우저에 JavaScript 컴파일러의 일부 버전이 출시되면 이는 더 큰 문제가 될 수 있습니다.Eval을 통해 실행된 코드는 이러한 최신 브라우저에 대해 나머지 JavaScript만큼 성능이 좋지 않을 수 있습니다.누군가 프로파일링을 해야 합니다.

이것은 eval과 이것이 어떻게 악이 아닌지에 대해 설명하는 좋은 기사 중 하나입니다.http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

나는 당신이 도망 가서 Eval ()를 어디에서나 사용해야한다고 말하는 것이 아닙니다.실제로, Eval ()를 실행하는 좋은 사용 사례는 거의 없습니다.코드 선명도, 디버깅 가능성 및 간과해서는 안되는 성능에 대한 우려가 분명히 있습니다.그러나 Eval ()가 의미가있는 경우가있을 때 사용하는 것을 두려워해서는 안됩니다.먼저 사용하지 말고 eval ()가 적절하게 사용될 때 코드가 더 깨지기 쉽거나 덜 안전하다고 생각하는 것을 두려워하지 마십시오.

eval()은 매우 강력하며 JS 문을 실행하거나 표현식을 평가하는 데 사용할 수 있습니다.그러나 문제는 eval()의 사용에 관한 것이 아니라 eval()로 실행하는 문자열이 악의적인 당사자의 영향을 받는 방식에 대해 말해 보겠습니다.결국에는 악성 코드가 실행됩니다.권력에는 큰 책임이 따릅니다.그러니 현명하게 사용하세요.이는 eval() 함수와 별로 관련이 없지만 이 문서에는 꽤 좋은 정보가 있습니다. http://blogs.popart.com/2009/07/javascript-injection-attacks/eval()의 기본 사항을 찾고 있다면 여기를 보십시오:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

나는 지금까지 말한 어떤 것도 반박하려고 시도하지 않을 것이지만 (내가 아는 한) 다른 방법으로는 수행될 수 없는 eval()의 사용을 제안할 것입니다.이를 코딩하는 다른 방법과 최적화하는 방법이 있을 수 있지만 실제로는 다른 대안이 없는 eval의 사용을 설명하기 위해 명확성을 위해 추가 기능 없이 직접 수행했습니다.그건:동적(또는 더 정확하게는) 프로그래밍 방식으로 생성된 개체 이름(값과 반대)

//Place this in a common/global JS lib:
var NS = function(namespace){
    var namespaceParts = String(namespace).split(".");
    var namespaceToTest = "";
    for(var i = 0; i < namespaceParts.length; i++){
        if(i === 0){
            namespaceToTest = namespaceParts[i];
        }
        else{
            namespaceToTest = namespaceToTest + "." + namespaceParts[i];
        }

        if(eval('typeof ' + namespaceToTest) === "undefined"){
            eval(namespaceToTest + ' = {}');
        }
    }
    return eval(namespace);
}


//Then, use this in your class definition libs:
NS('Root.Namespace').Class = function(settings){
  //Class constructor code here
}
//some generic method:
Root.Namespace.Class.prototype.Method = function(args){
    //Code goes here
    //this.MyOtherMethod("foo"));  // => "foo"
    return true;
}


//Then, in your applications, use this to instantiate an instance of your class:
var anInstanceOfClass = new Root.Namespace.Class(settings);

편집하다:그건 그렇고, 나는 (지금까지 지적한 모든 보안상의 이유로) 사용자 입력을 기반으로 개체 이름을 지정하는 것을 제안하지 않습니다.하지만 당신이 그렇게 하고 싶어할 어떤 타당한 이유도 상상할 수 없습니다.그래도 좋은 생각이 아니라는 점을 지적하고 싶다고 생각했습니다. :)

JavaScript 엔진에는 컴파일 단계에서 수행되는 다양한 성능 최적화 기능이 있습니다.이들 중 일부는 코드가 렉싱될 때 본질적으로 정적으로 분석할 수 있고 모든 변수 및 함수 선언이 있는 위치를 미리 결정할 수 있으므로 실행 중에 식별자를 확인하는 데 드는 노력이 줄어듭니다.

그러나 엔진이 코드에서 eval(..)을 발견하면 본질적으로 식별자 위치에 대한 모든 인식이 유효하지 않을 수 있다고 가정해야 합니다. 왜냐하면 렉싱 시 eval(..)에 전달할 코드가 무엇인지 정확하게 알 수 없기 때문입니다. 어휘 범위를 수정하거나 참조할 새 어휘 범위를 생성하기 위해 전달할 수 있는 객체의 내용을 수정합니다.

즉, 비관적인 의미에서 eval(..)이 있으면 최적화의 대부분은 의미가 없으므로 단순히 최적화를 전혀 수행하지 않습니다.

이것이 모든 것을 설명합니다.

참조 :

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#performance

항상 나쁜 생각은 아닙니다.예를 들어 코드 생성을 생각해 보십시오.나는 최근에 다음과 같은 라이브러리를 작성했습니다. 하이퍼바 사이의 격차를 해소하는 것 가상 돔 그리고 핸들바.핸들바 템플릿을 구문 분석하고 이를 다음으로 변환하여 이를 수행합니다. 하이퍼스크립트 이는 이후에 virtual-dom에 의해 사용됩니다.하이퍼스크립트는 먼저 문자열로 생성된 후 반환되기 전에 eval() 실행 가능한 코드로 변환하는 것입니다.나는 발견했다 eval() 이 특별한 상황에서는 악의 정반대입니다.

기본적으로

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

이에

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

성능 eval() 생성된 문자열을 한 번만 해석한 다음 실행 가능한 출력을 여러 번 재사용하면 되므로 이와 같은 상황에서는 문제가 되지 않습니다.

궁금하다면 코드 생성이 어떻게 이루어졌는지 확인할 수 있습니다. 여기.

나는 당신이 사용하면 실제로 중요하지 않다고 말할 것입니다 eval() 브라우저에서 실행되는 자바스크립트에서.*(주의)

모든 최신 브라우저에는 어쨌든 임의의 자바스크립트를 실행할 수 있는 개발자 콘솔이 있으며, 어느 정도 똑똑한 개발자라도 JS 소스를 보고 원하는 작업을 수행하기 위해 필요한 모든 부분을 개발자 콘솔에 넣을 수 있습니다.

*서버 엔드포인트가 사용자 제공 값의 올바른 검증 및 삭제를 갖고 있는 한, 클라이언트 측 자바스크립트에서 무엇을 구문 분석하고 평가하는지는 중요하지 않습니다.

사용하기에 적합하냐고 묻는다면 eval() 그러나 PHP에서는 대답은 다음과 같습니다. 아니요, 너가 아니라면 화이트리스트 평가문에 전달될 수 있는 모든 값.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top