자바 스크립트 평가 기능의 "부적절한 사용"은 무엇입니까? [닫은]


13

평가는 논란의 여지가 많은 언어 기능입니다. 더글러스 크로포드 플랫 아웃은 그것을 거부합니다. Eval이 어떤 특정 위험을 초래하는지 궁금합니다. 질문 에 따르면 Improper use of eval opens up your code for injection attacks.

Eval 명령의 부적절한 사용은 무엇이며 어떤 보안 취약점이 발생합니까?

답변:


31

내가 JScript 엔진을 구현했을 때 나는 EVAL IS EVIL 셔츠를 인쇄하는 것을 옹호 했지만 슬프게도 우리는 결코 그것을 피하지 못했습니다.

eval의 가장 큰 문제는 명백한 악성 코드 삽입 공격이 아니라는 점입니다. 그것의 가장 큰 문제는 사람들이 작은 문제를 해결하기 위해 그것을 정말로 큰 망치로 사용하는 경향이 있다는 것입니다. JScript 팀에있을 때 "eval"에 대해 실제로 본 대부분의 실제 사용법은 조회 테이블을 사용하여 간단하게 해결할 수있었습니다. JScript의 모든 객체는 이미 조회 테이블 이기 때문에 부담이되지 않았습니다. 평가는 다시 컴파일러를 시작 하고 완전히 코드를 최적화 할 수있는 컴파일러의 기능을 파괴한다 .

이 맥락에서 더 많은 생각을하려면 2003 년 주제에 관한 저의 기사를보십시오 :

일반적인 악 :

http://blogs.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx

주입 공격 악 :

http://blogs.msdn.com/b/ericlippert/archive/2003/11/04/53335.aspx


evalJSPacker와 같은 응용 프로그램이 좋아하는 방식으로 큰 코드 덩어리에 대해 어떻게 생각 하십니까? JSPacker + gzip은 일반적으로 자체 솔루션보다 파일 크기가 작지만, 올바르게 지적했듯이 본질적으로 동일한 코드에서 컴파일러를 두 번 실행하고 문자열 대체를 수행하는 오버 헤드가 발생합니다.
Matthew Scharley

2
@ 매튜 : 공간과 시간 사이에는 종종 트레이드 오프가 있으며, 그 트레이드 오프를 활용하는 것이 때로는 큰 승리 일 수 있습니다. 이 기술의 목적이 성능을 향상시키는 것이라면 제 생각에는 신중한 측정이 보안 허점을 도입하지 않고 현실적인 시나리오에서 중요한 승리를 보여 주면 훌륭하다는 것입니다. 그러나 세부 사항을 비판하는 특정 기술에 대해 충분히 알지 못합니다.
Eric Lippert

내가 보았던 답변 하나의 소원 중 하나를 여기 또는 SO 자체가 어떤 두 번째 링크 상태를 언급 한 것 : 그 eval()입니다 하지 클라이언트 (브라우저) 코드에 보안 위험.
sq33G

4

대부분의 보안 허점은 SQL 인젝션과 같은 종류의 허점, 즉 사용자 입력을 JavaScript 코드로 연결합니다. 차이점은 SQL에서 이런 일이 발생하지 않도록하는 방법이 있지만 JavaScript로 할 수있는 일은 많지 않다는 것입니다.

사소하고 쓸모없는 예로써, 간단한 JavaScript 계산기 :

textbox1.value = eval(textbox2.value);

올바른 사용 예 중 하나는 일반적인 단어를 뽑아서 짧은 1-2 문자로 바꾸어 JavaScript를 압축하는 일부 JavaScript 패커입니다. 그런 다음 패커는 생성 된 사전을 기반으로 문자열 대체 코드와 함께이 모든 것을 출력 한 다음 결과를 회피합니다.


1

평가 후면 같은 기능이없는 JS에서 할 불가능 몇 가지가 있습니다 ( eval, Function, 어쩌면 그 이상).

가지고 apply예를 들어. 일반 함수 호출에서 사용할 때 사용하기 쉽습니다.

foo.apply(null, [a, b, c])

그러나 새로운 구문을 통해 생성하는 객체에 대해서는 어떻게해야합니까?

new Foo.apply(null, [a, b, c]) 작동하지 않거나 유사한 형태가 아닙니다.

그러나 eval또는 Function( Function이 예제에서 사용) 을 통해이 제한을 해결할 수 있습니다 .

Function.prototype.New = (function () {
    var fs = [];
    return function () {
        var f = fs[arguments.length];
        if (f) {
            return f.apply(this, arguments);
        }
        var argStrs = [];
        for (var i = 0; i < arguments.length; ++i) {
            argStrs.push("a[" + i + "]");
        }
        f = new Function("var a=arguments;return new this(" + argStrs.join() + ");");
        if (arguments.length < 100) {
            fs[arguments.length] = f;
        }
        return f.apply(this, arguments);
    };
}) ();

예:

Foo.New.apply(null, [a, b, c]);

물론, Function.prototype.New사용 하는 함수를 수동으로 만들 수 는 있지만,이 장황하고 복잡 할뿐만 아니라 (정의 적으로) 유한해야합니다. Function코드가 여러 인수에 대해 작동하도록 허용합니다.


2
그러나 OP의 질문은 " Eval 명령을 부적절하게 사용하는 것은 무엇이며 어떤 보안 취약점이 있습니까? "가 아니라 " 잘 사용하는 것은 무엇입니까 eval()? "
Ross Patterson

1
@ RosPatterson : 나는 주로 질문의 제목 haha를 보았습니다.
Thomas Eding

그럼에도 불구하고, +1 :-) 나쁜 언어 기능에 대한 좋은 사용을 찾기위한
로스 패터슨

1

저에게 다소 직접적인 대답은 개발자 중심의 API 테스트 영역을 개발하는 것이 었습니다. 우리는 페이지에 텍스트 영역과 실행 버튼을주었습니다. 이 페이지의 핵심은 로컬 환경에서는 쉽지 않은 iframe 통신 API에 대해 Javascript로 시도해 볼 수 있다는 것입니다.

이 경우 악의적 인 작업은 개발자가 F12 도구를 열어서 수행했을 수도 있습니다.


0

나는 거의 사용되지 않아야한다는 것에 동의하지만에 대한 강력한 사용 사례를 찾았습니다 eval.

Firefox에는 asm.js라는 실험적인 새로운 기능이 있습니다. Javascript 언어의 제한된 하위 집합을 기본 코드로 컴파일 할 수 있습니다. 예, 이것은 매우 훌륭하지만 한계가 있습니다. Javascript의 제한된 하위 집합을 Javascript에 포함 된 C와 같은 언어로 생각할 수 있습니다. 실제로 사람이 읽거나 쓰는 것은 아닙니다.

Javascript의이 제한된 서브 세트는 컴파일 된 코드에서 런타임 생성 코드를 컴파일 된 코드에 삽입 할 수 없습니다.

사용자가 친숙한 표기법으로 수학 표현식을 작성하고 즉시 asm.js 코드로 변환 할 수있는 코드를 작성했습니다. 서버 측에서 코드를 처리하고 싶지 않다면 (필자가 아닌) eval브라우저에서 결과 코드를 실시간으로 처리 할 수있는 유일한 도구입니다.


0

다른 사람들이 지적했듯이, 작업 할 때 가장 중요한 것은 eval안전하게 유지하는 것입니다. 이를 위해서는 인수 검사를 철저히 수행 eval하고 런타임 생성 코드를 유지하고 보호하는 것이 일반적으로 훨씬 어렵 기 때문에 코드를 단순하게 유지하려고합니다.

즉, 나는 eval두 가지 종류의 것을 사용 하는 것을 즐깁니다 (아마도 더 좋고 덜 악의적 인 대안이있을지라도).

  1. eval"명시 적으로 캐싱 코드"방법 이므로 성능을 향상시키는 데 사용할 수 있습니다. 옵티마이 저는 항상 개선되고 있지만, 그들이 당신을 위해 무엇을 할 수 있는지에 대한 보장은 없습니다. 코드에서 일을 명시 적으로 지정하면 실제로 옵티마이 저가보다 현명한 결정을 내릴 수 있습니다.
  2. 또한 성능 저하없이 JS에없는 다른 언어 기능뿐만 아니라 기본 형식 안전 형식을 제공하는 데 사용할 수 있습니다.

예를 들어, 이 사전 컴파일 된 객체 반복자 접근 방식eval 은 객체 속성 반복에 사용할 때 명확한 성능 이점을 보여줍니다 . 또한 비용이 거의 들지 않으면서도 암시 적 제약 조건 검사 및 그 이상을 제공 할 수있는 강력한 유형 시스템의 시작을 보여줍니다.

많은 노련한 Javascript 개발자는 아마도 이것이 토끼 구멍이라고 지적 할 것입니다. Javascript를 이런 식으로 작성하기 시작하면 언어 사용 방식을 근본적으로 변경하기 때문입니다. 그러나 자바 스크립트를 좋아하는 사람들에게는 반드시 나쁜 것은 아니지만 언어 자체의 사용 방식을 변경해야만 달성 할 수있는 기본 언어 기능이 누락되었습니다.


-3

eval이 갈 길처럼 보이는 상황이 있는데 문자열을 평가하고 이름이 문자열과 동일한 기존 변수를 반환합니다.

table1ResultsTable, table2ResultsTable, tableNResultsTable과 같은 여러 테이블이 있습니다. jQuery 데이터 테이블 객체와 같은 이름으로 변수를 설정했습니다. 이를 사용하여 테이블을 설정하고 jQuery 데이터 테이블 함수를 호출합니다.

각 테이블에는 class = "resultsTable"이 할당되어 있습니다. 이제 테이블을 클릭 할 때 변수를 가져와야합니다. 나는 이것을하고있다 :

$('resultsTable).on('click', 'td', function(event) {
    var cResultsTable = eval(event.target.parentElement.parentElement.parentElement.id);
    [etc]
});

그래서 셀을 클릭 한 테이블의 id를 얻습니다.이 테이블은 해당하는 datatable 객체 변수와 동일한 이름을 갖습니다. 누군가 개선에 대한 제안이 있으면 그것에 대해 알고 싶습니다.


1
왜 평가가 필요한가요? ID는 코드가 아닌 일반 문자열이어야합니다. 어쨌든 event.target.parentElement.parentElement.parentElement끔찍하다. 또한, 평가 가능한 ID를 의도적으로 사용하지 않는 한 (참조 오류 : [id] 정의되지 않음 ") 오류를 eval 호출로 생성 할 것으로 예상됩니다. 중복 ID 생성).
Brian

아마도 나는 자신을 명확하게하지 않을 것입니다. id는 일반 문자열입니다. 클릭 한 테이블의 ID입니다. 또한 id와 이름이 같은 객체 변수 (jQuery datatable () 메소드로 설정, 동일한 테이블 참조)가 있습니다. 테이블을 클릭 할 때 해당 변수를 가져 와서 해당 함수에 액세스하려고합니다 (실제로 "row_selected"클래스를 선택한 행에 추가하려고합니다). 나는 이것을 썼기 때문에 개선을 생각해 냈습니다. 방금 모든 객체 참조를 배열에 넣고 요소의 이름을 id와 동일하게 지정하고 id 문자열을 그에 연결하여 객체 참조를 가져옵니다.
BobRodes

브라이언, 클릭 한 테이블의 id를 찾는 더 좋은 방법이 있다면, 저는 귀가됩니다. datatables 함수의 경우 셀에 대한 click 이벤트를 처리하고 row_selected 클래스를 parentNode에 추가해야합니다. 행 이벤트를 처리하고 클래스를 직접 추가 할 수없는 이유는 무엇입니까?하지만 행을 선택하면 행이 선택된 것으로 표시되지 않습니다.
BobRodes

1
아마도 나는 자신을 명확하게하지 않을 것입니다. 일반 (JS 이외의) 문자열에서 eval을 호출하면 예외가 발생합니다. 따라서 평가 사용은 의미가 없습니다. id와 같은 이름으로 객체 변수를 생성하면 코드가 작동하지만 깨지는 것처럼 보입니다. 차라리 변수를 사용하여 변수를 만들고 싶습니다 document.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE. Eric Lippert가 지적했듯이 "JScript의 모든 객체는 이미 조회 테이블입니다."
Brian

자, 요소 참조에 속성을 추가하고 데이터 테이블 개체 참조로 설정하려고합니까? 나에게도 더 빡빡하게 들린다.
BobRodes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.