programing

왜 JavaScript 평가 기능을 사용하는 것이 나쁜 생각일까요?

coolbiz 2023. 1. 17. 21:46
반응형

왜 JavaScript 평가 기능을 사용하는 것이 나쁜 생각일까요?

eval 함수는 코드를 동적으로 생성하는 강력하고 쉬운 방법인데 주의사항은 무엇입니까?

  1. eval을 잘못 사용하면 주입 공격에 대한 코드가 열립니다.

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

  3. eval'd 코드가 느리게 실행됨(eval'd 코드를 컴파일/캐시할 기회가 없음)

편집: @Jeff Walden이 코멘트에서 지적한 바와 같이, #3은 2008년에 비해 현재 그다지 사실이 아닙니다.단, 컴파일된 스크립트의 캐싱이 일부 발생할 수 있지만 이는 수정 없이 eval'd를 반복하는 스크립트로만 제한됩니다.보다 가능성이 높은 시나리오는 매번 약간의 수정을 거쳐 캐시할 수 없었던 스크립트를 평가하는 것입니다.어떤 eval'd 코드가 더 느리게 실행된다고 칩시다.

평가가 항상 나쁜 것만은 아닙니다.그게 딱 맞을 때가 있어요.

그러나 평가는 현재, 그리고 역사적으로 자신이 무엇을 하고 있는지 모르는 사람들에 의해 과도하게 사용되고 있습니다.안타깝게도 여기에는 JavaScript 튜토리얼을 작성하는 사람들이 포함되어 있으며, 경우에 따라서는 보안에 영향을 줄 수도 있고, 더 많은 경우 단순한 버그가 발생할 수도 있습니다.따라서 평가보다 물음표를 더 많이 찍을수록 좋습니다.eval을 사용할 때는 항상 자신이 하고 있는 일을 온전하게 체크할 필요가 있습니다.왜냐하면 보다 안전하고 깨끗한 방법으로 할 수 있기 때문입니다.

일반적인 예를 들어, 변수 '감자'에 저장된 ID로 요소의 색상을 설정하려면:

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

위의 코드의 작성자가 JavaScript 오브젝트가 어떻게 동작하는지에 대한 기본을 알고 있다면 평가의 필요성을 없애면서 문자 그대로의 닷 이름 대신 대괄호를 사용할 수 있다는 것을 깨달았을 것입니다.

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

읽기 쉽고 버그가 적을 수 있습니다.

(하지만, 그 때, 그들이 무엇을 하고 있는지/정말/알고 있는/누군가는 이렇게 말할 것이다:

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

이는 문서 객체에서 직접 DOM 요소에 액세스하는 오래된 트릭보다 신뢰성이 높습니다.)

문자열에서 자바스크립트 함수를 실행할 수 있기 때문이라고 생각합니다.이를 사용하면 사람들이 악성 코드를 응용 프로그램에 쉽게 주입할 수 있습니다.

두 가지 점이 떠오릅니다.

  1. 보안(단, 사용자가 직접 평가할 문자열을 생성하는 한 이는 문제가 되지 않을 수 있음)

  2. 성능: 실행할 코드를 알 수 없는 경우 최적화할 수 없습니다.(javascript와 퍼포먼스에 대해서, 확실히 Steve Yegge의 프레젠테이션)

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

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

주로 유지 보수와 디버깅이 훨씬 어렵습니다.마치...goto사용할 수 있지만, 문제를 찾기 어려워지고 나중에 수정해야 할 사람들에게도 어려워집니다.

한 가지 유의할 점은 eval()을 사용하여 제한된 환경에서 코드를 실행할 수 있다는 것입니다.특정 JavaScript 함수를 차단하는 소셜 네트워킹 사이트는 때때로 eval 블록으로 분할하여 속일 수 있습니다.

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

따라서 다른 방법으로는 허용되지 않을 수 있는 자바스크립트 코드를 실행하려는 경우(Myspace, I are weeking you...) eval()이 유용한 트릭이 될 수 있습니다.

그러나 위에서 언급한 모든 이유로 인해 사용자가 완전히 제어할 수 있는 자체 코드에 이 기능을 사용하면 안 됩니다. 이 기능은 필요하지 않을 뿐 아니라 '교묘한 JavaScript 해킹' 쉘프에 맡겨야 합니다.

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

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

이는 잠재적인 보안 위험으로 실행 범위가 다르며 코드 실행을 위한 완전히 새로운 스크립트 환경을 생성하기 때문에 매우 비효율적입니다.자세한 내용은 eval을 참조하십시오.

단, 이 기능은 매우 유용하며, 적당히 사용하면 많은 기능을 추가할 수 있습니다.

평가 대상 코드가 신뢰할 수 있는 소스(일반적으로 사용자 자신의 애플리케이션)에서 온 것임을 100% 확신하지 않는 한 시스템을 사이트 간 스크립팅 공격에 노출시킬 수 있는 확실한 방법입니다.

어떤 맥락에서 사용하는지 알면 그렇게 나쁘지만은 않습니다.

이 「」를 사용하고 .eval()XMLHttpRequest에서 사용자 사이트로 돌아온 일부 JSON에서 신뢰할 수 있는 서버 측 코드로 작성된 개체를 만드는 것은 문제가 되지 않습니다.

신뢰할 수 없는 클라이언트 측 JavaScript 코드로는 그렇게 많은 작업을 수행할 수 없습니다.이 실행하고 있는eval()★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★♪

보안에 대한 신뢰도가 크게 떨어집니다.

사용자가 논리 함수를 입력하고 AND를 평가하도록 하려면 JavaScript 평가 기능이 완벽합니다.과 「」를 할 수 .eval(uate) string1 === string2 등등.

코드에서 eval()의 사용을 발견했을 경우, "eval() is evil"이라는 만트라에 유의하십시오.

이 함수는 임의의 문자열을 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에서 라이브러리를 사용할 수 있습니다.

을 to한 strings로 한다는 것도 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);

새로운 Function() 컨스트럭터의 사용은 eval()과 비슷하므로 신중하게 접근해야 합니다.그것은 강력한 구성물이 될 수 있지만 종종 오용된다. ""를 사용해야 하는 eval()Function()은 Function ( ) 。

새로운 Function()에서 평가된 코드가 로컬 함수 범위에서 실행되므로 평가 대상 코드에서 var로 정의된 변수는 자동으로 전역이 되지 않습니다.

자동 글로벌을 방지하는 또 다른 방법은 포장을 하는 것입니다.eval()시시기기기기발발발발발호

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

차세대 브라우저가 JavaScript 컴파일러의 일부 플레이버와 함께 출시되기 때문에 이는 더욱 문제가 될 수 있습니다.Eval을 통해 실행되는 코드는 이러한 새로운 브라우저에 대해 다른 JavaScript만큼 성능이 좋지 않을 수 있습니다.누군가는 프로파일링을 해야 해

이것은 평가와 그것이 악이 아닌 방법에 대해 설명하는 좋은 기사 중 하나입니다.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

JavaScript Engine에는 컴파일 단계에서 수행하는 여러 가지 성능 최적화가 있습니다.이들 중 일부는 기본적으로 코드가 렉스할 때 코드를 정적으로 분석하고 모든 변수와 함수 선언이 어디에 있는지 미리 결정할 수 있기 때문에 실행 중에 식별자를 해결하는 데 드는 노력이 줄어듭니다.

단, 엔진에서는 코드 내에서 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

항상 나쁜 생각만은 아니다.코드 생성을 예로 들 수 있습니다.는 최근에 하이퍼바라는 도서관을 썼는데, 가상돔과 핸들바를 연결하는 역할을 합니다.이를 위해 핸들바 템플릿을 해석하여 하이퍼스크립트로 변환하고 이후 가상 도메인에서 사용됩니다.하이퍼스크립트가 문자열로 먼저 생성되고 반환되기 전에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()자바스크립트)*(sat)

모든 최신 브라우저에는 임의의 Javascript를 실행할 수 있는 개발자 콘솔이 있으며, 준스마트 개발자는 JS 소스를 보고 필요한 부분을 개발 콘솔에 넣을 수 있습니다.

*사용자의 서버 엔드포인트가 사용자 제공 값의 올바른 검증과 위생을 가지고 있는 한 클라이언트 측 Javascript에서 무엇이 해석되고 평가되는지는 중요하지 않습니다.

eval()그러나 PHP에서는 평가문에 전달될 수 있는 값을 화이트리스트에 올리지 않는 한 대답은 NO입니다.

가비지 컬렉션

브라우저 가비지 컬렉션은 평가 대상 코드를 메모리에서 제거할 수 있는지 여부를 모르기 때문에 페이지가 새로고침될 때까지 저장된 상태로 유지합니다.사용자가 바로 페이지에 접속할 수 있다면 나쁘지 않지만 웹 앱에 문제가 될 수 있습니다.

다음은 문제를 시연하는 스크립트입니다.

https://jsfiddle.net/CynderRnAsh/qux1osnw/

document.getElementById("evalLeak").onclick = (e) => {
  for(let x = 0; x < 100; x++) {
    eval(x.toString());
  }
};

위의 코드와 같은 간단한 것으로 인해 앱이 종료될 때까지 소량의 메모리가 저장됩니다.이것은 평가된 스크립트가 자이언트 함수이며 인터벌로 호출된 경우 더욱 악화됩니다.

지금까지 말한 것에 대해서는 반박하지 않겠습니다만, (제가 아는 한) 다른 방법으로는 할 수 없는 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);

편집: 덧붙여서, 지금까지 지적된 모든 보안상의 이유로, 사용자 입력에 근거해 오브젝트명을 지정하는 것은 추천하지 않습니다.하지만 당신이 그렇게 하고 싶어하는 좋은 이유를 짐작할 수 없어요.그래도 좋은 생각이 아니라고 지적하고 싶었지만:)

언급URL : https://stackoverflow.com/questions/86513/why-is-using-the-javascript-eval-function-a-bad-idea

반응형