문제

쓰고 있어요 일부는 JavaScript 코드에 구문 분석하는 사용자가 입력한 기능(위해 스프레드시트)입니다.데 분석 화학식 I 변환로 자바스크립트 및 실행 eval() 에서 그것을 얻은 결과입니다.

그러나 나는 항상 멀리 주저에서 사용하는 eval() 면 내가 그것을 피할 수 있기 때문에 그것은 악한(그리고,바르게 또는 잘못했다고 생각했다 더 악한 자바 스크립트에서이기 때문에 코드를 평가할 수 있는 사용자에 의해 변경 될).

그래서 때,그것은 그것을 사용하는 것이 확인?

도움이 되었습니까?

해결책

귀하의 질문의 전제를 다루기 위해 잠시 시간을 내고 싶습니다.사악한". 단어"사악한", 언어를 프로그래밍하는 사람이 사용하는대로 일반적으로"위험한 "또는 더 정확하게"단순하게 보이는 명령에 많은 해를 끼칠 수 있습니다 "를 의미합니다. 따라서 위험한 것을 사용하는 것은 언제입니까? 위험이 무엇인지 알 때 적절한 예방 조치를 취할 때입니다.

시점까지, eval ()의 사용의 위험을 살펴 보겠습니다. 다른 모든 것과 마찬가지로 작은 숨겨진 위험이 많을 것입니다. 그러나 Eval ()가 악으로 간주되는 이유는 성능과 코드 주입입니다.

  • Performance -Eval ()는 인터프리터/컴파일러를 실행합니다. 코드가 컴파일 된 경우 런타임 중간에 무거운 컴파일러를 호출해야하기 때문에 큰 타격입니다. 그러나 JavaScript는 여전히 대부분 해석 된 언어이며, 이는 Eval ()을 Calling ()는 일반적인 경우에 큰 성능이 아니지만 아래의 특정 언급을 참조하십시오).
  • 코드 주입 - 평가 ()는 잠재적으로 높은 권한 하에서 일련의 코드를 실행할 수 있습니다. 예를 들어, 관리자/루트로 실행되는 프로그램은 () 사용자 입력을 평가하고 싶지 않습니다. 해당 입력은 잠재적으로 "rm -rf/etc/requivent -file"또는 더 나빠질 수 있기 때문입니다. 다시 말하지만, 브라우저의 JavaScript에는 프로그램이 사용자 자체 계정으로 실행되기 때문에 해당 문제가 없습니다. 서버 측 JavaScript는 그 문제를 가질 수 있습니다.

특정 사례에. 내가 이해 한 바에 따르면, 당신은 문자열을 직접 생성하고 있으므로 "RM -RF 중요한 것"과 같은 문자열을 생성하지 않도록주의하면 코드 주입 위험이 없지만 기억하십시오. 매우 힘들다 일반적인 경우에 이것을 보장하기 위해). 또한 브라우저에서 실행중인 경우 코드 주입은 매우 작은 위험이라고 생각합니다.

성능에 관해서는 코딩의 용이성에 대비하여 가중치가 있어야합니다. 공식을 구문 분석하는 경우 다른 구문 분석기를 실행하지 않고 구문 분석 중에 결과를 계산할 수 있다고 생각합니다 (내부 Eval ()). 그러나 Eval ()을 사용하여 코딩하기가 더 쉬울 수 있으며 성능 히트는 눈에 띄지 않을 것입니다. 이 경우 Eval ()가 시간을 절약 할 수있는 다른 기능보다 더 악한 일이 아닙니다.

다른 팁

eval() 악이 아닙니다. 또는 그렇다면 반사, 파일/네트워크 I/O, 스레딩 및 IPC가 다른 언어로 "악한"것과 같은 방식으로 악합니다.

만약에, 당신의 목적을 위해, eval() 수동 해석보다 빠르거나 코드를 더 단순하거나 명확하게 만듭니다 ... 그러면 사용해야합니다. 둘 다하지 않으면 당신은 안됩니다. 그렇게 간단합니다.

신뢰할 수 있는 경우에는 소스입니다.

의 경우에는 JSON,그것은 더 많거나 적은 힘으로 변경 소스기 때문에,그것은 오는 웹 서버에서 당신을 제어합니다.한 JSON 자신 데이터가 포함되지 않은 사용자는 업로드,더 주요 단점은 사용된다.

다른 모든 경우에서 나는 좋은 길이도록 사용자 제공 데이터에 부합하는 내 규칙을 공급하기 전에 그것을 eval().

진짜 사람들을 얻자 :

  1. 모든 주요 브라우저는 이제 해커가 풍부하게 사용할 수있는 내장 콘솔이있어 모든 값으로 모든 기능을 호출 할 수 있습니다. 왜 가능하더라도 평가 명세서를 사용하는 이유는 무엇입니까?

  2. JavaScript의 2000 라인을 컴파일하는 데 0.2 초가 걸리면 JSON 4 줄을 평가하면 성능 저하는 무엇입니까?

Crockford의 'Eval Is Evil'에 대한 설명조차도 약합니다.

평가 기능은 Evil이고 Eval 기능은 JavaScript의 가장 잘못 사용되는 기능입니다. 피하십시오

Crockford 자신은 "이런 종류의 진술은 비이성적 인 신경증을 생성하는 경향이 있습니다. 사지 마십시오."

평가를 이해하고 그것이 유용한시기를 아는 것이 더 중요합니다. 예를 들어, Eval은 소프트웨어에서 생성 한 서버 응답을 평가하기위한 현명한 도구입니다.

btw : prototype.js 호출은 Eval을 다섯 번 직접 (Evaljson () 및 EvalResponse () 포함). JQuery는 Parsejson (기능 생성자를 통해)에서 사용합니다.

나는 따르는 경향이있다 크록 포드의 조언 ~을 위한 eval(), 그리고 그것을 완전히 피하십시오. 그것을 요구하는 것처럼 보이는 방법조차도 그렇지 않습니다. 예를 들어, setTimeout() 평가 대신 함수를 전달할 수 있습니다.

setTimeout(function() {
  alert('hi');
}, 1000);

그럼에도 불구하고 신뢰할 수 있습니다 소스, 나는 그것을 사용하지 않습니다. JSON이 반환 한 코드는 잡화 될 수 있기 때문에 최악의 상황에서 나쁜 일을 할 수있는 일을 할 수 있습니다.

평가는 코드를 템플릿하는 데 사용되는 컴파일에 보완적인 것입니다. 템플릿을 통해 개발 속도를 높이는 유용한 템플릿 코드를 생성하는 단순화 된 템플릿 생성기를 작성한다는 것을 의미합니다.

개발자가 Eval을 사용하지 않는 프레임 워크를 작성했지만 프레임 워크를 사용하여 프레임 워크가 템플릿을 생성하기 위해 Eval을 사용해야합니다.

다음 방법을 사용하여 Eval의 성능을 높일 수 있습니다. 스크립트를 실행하는 대신 함수를 반환해야합니다.

var a = eval("3 + 5");

그것은 다음과 같이 구성해야합니다

var f = eval("(function(a,b) { return a + b; })");

var a = f(3,5);

캐싱 f는 확실히 속도를 향상시킬 것입니다.

또한 Chrome은 이러한 기능을 매우 쉽게 디버깅 할 수 있습니다.

보안과 관련하여 Eval을 사용하는지 여부는 아무런 차이가 없습니다.

  1. 우선, 브라우저는 샌드 박스에서 전체 스크립트를 호출합니다.
  2. Eval에서 악한 모든 코드는 브라우저 자체에서 악합니다. 공격자 또는 다른 사람은 DOM에서 스크립트 노드를 쉽게 주입하고 무엇이든 평가할 수 있다면 무엇이든 할 수 있습니다. 평가를 사용하지 않으면 아무런 차이가 없습니다.
  3. 유해한 서버 측 보안은 대부분 열악합니다. 쿠키가 열악한 검증 또는 서버에서 ACL 구현이 좋지 않으면 대부분의 공격이 발생합니다.
  4. 최근 Java 취약성 등이 Java의 기본 코드에있었습니다. JavaScript는 샌드 박스에서 실행되도록 설계되었으며 애플릿은 인증서 등이있는 샌드 박스 밖에서 실행되도록 설계되어 취약점 및 기타 여러 가지로 이어졌습니다.
  5. 브라우저를 모방하기위한 코드 작성은 어렵지 않습니다. 좋아하는 사용자 에이전트 문자열로 서버에 HTTP 요청을하는 것만 큼해야합니다. 어쨌든 모든 테스트 도구 조롱 브라우저; 공격자가 당신에게 해를 끼치려면 Eval은 그들의 마지막 수단입니다. 서버 측 보안을 처리하는 다른 많은 방법이 있습니다.
  6. 브라우저 DOM은 사용자 이름이 아닌 파일에 액세스 할 수 없습니다. 실제로 평가하는 기계에는 아무것도 액세스 할 수 없습니다.

서버 측 보안이 누군가가 어디에서나 공격 할 수있을 정도로 견고한 경우, Eval에 대해 걱정하지 않아야합니다. 앞서 언급했듯이 Eval이 존재하지 않으면 공격자는 브라우저의 평가 기능에 관계없이 서버를 해킹 할 수있는 많은 도구가 있습니다.

Eval은 미리 사용하지 않은 것을 기반으로 복잡한 문자열 처리를 수행하기 위해 일부 템플릿을 생성하는 데만 좋습니다. 예를 들어, 나는 선호합니다

"FirstName + ' ' + LastName"

반대로

"LastName + ' ' + FirstName"

내 디스플레이 이름으로, 데이터베이스에서 나올 수 있고 하드 코딩되지 않은 것이 아닙니다.

나는 사람들이 평가를 사용하지 않는 것을 옹호하는 것을 보았습니다. 사악한, 그러나 나는 같은 사람들이 함수와 설정 타임 아웃을 동적으로 사용하는 것을 보았으므로 Eval을 사용합니다. 후드 아래 :디

BTW, 샌드 박스가 충분하지 않은 경우 (예를 들어, 코드 주입을 허용하는 사이트에서 작업하는 경우) 평가는 마지막 문제입니다. 보안의 기본 규칙은 그 것입니다 모두 입력은 사악하지만 JavaScript의 경우 조차 JavaScript 자체는 사악 할 수 있습니다. JavaScript에서는 모든 기능을 덮어 쓸 수 있으며 실제 기능을 사용하는지 확신 할 수 없으므로 악의적 인 코드가 시작되면 JavaScript 내장을 믿을 수 없습니다. 기능 : d

이제이 게시물의 에필로그는 다음과 같습니다.

만약 너라면 진짜 필요합니다 (시간의 80% Eval은 아니다 필요) 그리고 당신은 당신이하는 일을 확신하고, 그냥 평가 (또는 더 나은 기능;)), 클로저 및 OOP는 다른 종류의 논리를 사용하여 평가를 대체 할 수있는 케이스의 80/90%를 커버합니다. 동적으로 생성 된 코드입니다 (예 : 통역사를 작성하는 경우) 및 이미 JSON 평가를 평가했듯이 (여기에서 Crockford Safe Evaluation;)).

크롬에서 디버깅을 할 때 (v28.0.1500.72), 변수가 폐쇄를 생성하는 중첩 된 함수에 사용되지 않으면 폐쇄에 바인딩되지 않음을 발견했습니다. 나는 그것이 JavaScript 엔진의 최적화라고 생각합니다.

하지만: 언제 eval() 폐쇄를 일으키는 함수 내부에서 사용됩니다. 모두 외부 함수의 변수는 전혀 사용하지 않더라도 폐쇄에 바인딩됩니다. 누군가가 메모리 누출을 생성 할 수 있는지 테스트 할 시간이 있다면 아래에 의견을 남겨주세요.

내 테스트 코드는 다음과 같습니다.

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is visible in debugger
            eval("1");
        })();
    }

    evalTest();
})();

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is NOT visible in debugger
            var noval = eval;
            noval("1");
        })();
    }

    evalTest();
})();

(function () {
    var noval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();    // Variable "unused" is NOT visible in debugger
            noval("1");
        })();
    }

    evalTest();
})();

내가 여기서 지적하고 싶은 것은, 그 eval ()가 반드시 네이티브를 언급해서는 안된다는 것입니다. eval() 기능. 그것은 모두 함수의 이름에 달려 있습니다. 그래서 원주민을 부를 때 eval() 별칭 이름이 있습니다 (예 : var noval = eval; 그런 다음 내부 기능으로 noval(expression);) 그런 다음 평가 expression 폐쇄의 일부가되어야하지만 실제로는 그렇지 않은 변수를 지칭 할 때 실패 할 수 있습니다.

Microsoft는 IE 블로그의 브라우저에서 Eval ()가 속도가 느린 이유를 설명합니다. IE+JavaScript 성능 권장 사항 2 부 : JavaScript 코드 비 효율성.

Eval ()를 사용해야 할 때 유일한 인스턴스는 동적 JS를 즉석에서 실행해야 할 때입니다. 서버에서 비동기로 다운로드 한 JS에 대해 이야기하고 있습니다 ...

... 그리고 10의 9 번, 당신은 리팩토링을 통해 쉽게 그렇게하지 않을 수 있습니다.

그것은 괜찮은 그것을 사용하면 완전히 제어할 수 있는 코드의 전달 eval 기능입니다.

eval 거의 올바른 선택이 아닙니다. 스크립트를 함께 연결하고 즉시 실행하여 달성해야 할 일을 달성 할 수있는 수많은 사례가있을 수 있지만, 일반적으로 처분에 훨씬 더 강력하고 유지 관리 가능한 기술이 있습니다.obj["prop"] 와 같다 obj.prop), 클로저, 객체 지향 기술, 기능 기술 - 대신 사용하십시오.

클라이언트 스크립트가 진행되는 한, 보안 문제는 무의미한 요점이라고 생각합니다. 브라우저에로드 된 모든 것은 조작의 대상이되며 그렇게 취급해야합니다. 브라우저의 URL 막대와 같이 DOM에서 JavaScript 코드를 실행하거나 DOM의 객체를 조작하는 방법이 훨씬 쉬운 경우 Eval () 문을 사용하는 데 위험이 없습니다.

javascript:alert("hello");

누군가가 DOM을 조작하고 싶다면 나는 스윙을 말한다. 모든 유형의 공격을 방지하기위한 보안은 항상 서버 응용 프로그램, 기간의 책임이어야합니다.

실용적 관점에서 볼 때, 그렇지 않으면 일을 할 수있는 상황에서 Eval ()를 사용하는 데 도움이되지 않습니다. 그러나 평가를 사용해야하는 특정 사례가 있습니다. 그렇다면 페이지를 날려 버릴 위험없이 확실히 수행 할 수 있습니다.

<html>
    <body>
        <textarea id="output"></textarea><br/>
        <input type="text" id="input" />
        <button id="button" onclick="execute()">eval</button>

        <script type="text/javascript">
            var execute = function(){
                var inputEl = document.getElementById('input');
                var toEval = inputEl.value;
                var outputEl = document.getElementById('output');
                var output = "";

                try {
                    output = eval(toEval);
                }
                catch(err){
                    for(var key in err){
                        output += key + ": " + err[key] + "\r\n";
                    }
                }
                outputEl.value = output;
            }
        </script>
    <body>
</html>

JavaScript의 Eval ()는 언제 악하지 않습니까?

나는 항상 노력하고 있습니다 평가 사용을 방해합니다. 거의 항상 더 깨끗하고 유지 관리 가능한 솔루션을 사용할 수 있습니다. 평가 JSON 구문 분석조차 필요하지 않습니다. 평가 유지 보수 지옥에 추가됩니다. 이유 없이는 Douglas Crockford와 같은 마스터들에 의해 눈살을 찌푸립니다.

그러나 나는 그것이 어디에 있는지 한 가지 예를 찾았습니다 해야한다 사용된:

표현을 통과해야 할 때.

예를 들어, 나는 일반을 구성하는 기능이 있습니다. google.maps.ImageMapType 나를 위해 객체이지만 레시피를 말해야합니다. 어떻게 타일 URL을 구축해야합니까? zoom 그리고 coord 매개 변수 :

my_func({
    name: "OSM",
    tileURLexpr: '"http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png"',
    ...
});

function my_func(opts)
{
    return new google.maps.ImageMapType({
        getTileUrl: function (coord, zoom) {
            var b = zoom;
            var a = coord;
            return eval(opts.tileURLexpr);
        },
        ....
    });
}

사용의 예 eval: 수입.

일반적으로 어떻게 끝나는 지.

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

그러나 도움으로 eval 그리고 약간의 도우미 기능은 훨씬 더 나은 모양을 얻습니다.

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

importable (이 버전은 콘크리트 멤버 가져 오기를 지원하지 않습니다).

function importable(path) {
    var name;
    var pkg = eval(path);
    var result = '\n';

    for (name in pkg) {
        result += 'if (name !== undefined) throw "import error: name already exists";\n'.replace(/name/g, name);
    }

    for (name in pkg) {
        result += 'var name = path.name;\n'.replace(/name/g, name).replace('path', path);
    }
    return result;
}

서버 측에서 평가는 SQL 또는 InfluxDB 또는 Mongo와 같은 외부 스크립트를 처리 할 때 유용합니다. 서비스를 재배치하지 않고 런타임시 사용자 정의 유효성 검사를 수행 할 수 있습니다.

예를 들어 다음 메타 데이터가 포함 된 업적 서비스

{
  "568ff113-abcd-f123-84c5-871fe2007cf0": {
    "msg_enum": "quest/registration",
    "timely": "all_times",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/registration:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/registration\"}`"
  },
  "efdfb506-1234-abcd-9d4a-7d624c564332": {
    "msg_enum": "quest/daily-active",
    "timely": "daily",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" WHERE time >= '${today}' ${ENV.DAILY_OFFSET} LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/daily-active:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/daily-active\"}`"
  }
}

그런 다음 허용하고

  • JSON에서 문자 그대로 문자열을 통해 객체/값의 직접 주입, 텍스트 템플릿에 유용합니다.

  • 비교기로 사용할 수 있습니다. CMS에서 퀘스트 또는 이벤트를 검증하는 방법을 규칙을 작성한다고 가정 해

이것의 사기 :

  • 완전히 테스트되지 않은 경우 코드의 오류가 될 수 있으며 서비스의 물건을 분해 할 수 있습니다.

  • 해커가 시스템에 스크립트를 작성할 수 있다면 거의 나사가됩니다.

  • 스크립트를 검증하는 한 가지 방법은 스크립트의 해시를 안전한 곳에 안전하게 유지하므로 실행하기 전에 확인할 수 있습니다.

나는 평가를 정당화하는 사례가 드물다고 생각합니다. 당신은 그것을 사용할 가능성이 더 높습니다. 실제로 정당화.

보안 문제가 가장 잘 알려져 있습니다. 또한 JavaScript는 JIT 컴파일을 사용하며 이는 Eval에서 매우 잘 작동합니다. Eval은 컴파일러에 대한 Blackbox와 다소 다소 있으며 JavaScript는 성능 최적화 및 범위를 안전하고 올바르게 적용하기 위해 어느 정도 (어느 정도) 코드를 미리 예측할 수 있어야합니다. 경우에 따라 성능 영향은 외부의 다른 코드에도 영향을 줄 수 있습니다.

더 알고 싶다면 :https://github.com/getify/you-dont-know-js/blob/master/scope%20%26%20closures/ch2.md#eval

가능한 경우 테스트 중에 만. 또한 Eval ()는 다른 특수 JSON 등 평가자보다 훨씬 느립니다.

코드 생성. 나는 최근에라는 도서관을 썼다 하이퍼 바 그 사이의 간격을 연결합니다 가상 -M 그리고 핸들 바. 핸들 바 템플릿을 구문 분석하고 변환하여이를 수행합니다. hyperscript. hyperscript는 먼저 문자열로 생성됩니다. 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 ()를 사용하지 않을 이유가 없습니다. 비록 그가 평가 () 함수로 전송되는 것을 조작 할 수 있지만 웹 사이트의 소스 코드를 조작 할 수 있기 때문에 JavaScript 코드 자체를 변경할 수 있기 때문에 보안 문제가 아닙니다.

그래서 ... 언제 anvate ()를 사용하지 않습니까? 평가 ()는 제 3자가 변경할 수있는 기회가있을 때만 사용해서는 안됩니다. 클라이언트와 서버 간의 연결을 가로 채는 것과 같습니다 (그러나 문제가있는 경우 HTTPS를 사용하십시오). 포럼과 같은 다른 사람들이 작성한 코드를 구문 분석하지 않아야합니다.

실제로 필요한 경우 평가는 악하지 않습니다. 그러나 내가 걸려 넘어지는 Eval 사용의 99.9%는 ~ 아니다 필요 (세트 타임 아웃 포함).

나에게 악은 성과 나 보안 문제가 아닙니다 (글쎄, 간접적으로 둘 다). 이러한 모든 불필요한 Eval 사용은 유지 보수 지옥에 추가됩니다. 리팩토링 도구가 버려집니다. 코드 검색은 어렵습니다. 그 evals의 예상치 못한 효과는 군단입니다.

내 믿음은 Eval은 클라이언트 측 웹 애플리케이션에 매우 강력한 기능이며 안전합니다. :-) 보안 문제는 본질적으로 서버 측 문제입니다. 이제 FireBug와 같은 도구를 사용하면 JavaScript 응용 프로그램을 공격 할 수 있기 때문입니다.

평가는 매크로가 없을 때 코드 생성에 유용합니다.

(어리석은) 예를 위해, 당신이 쓰고 있다면 Brainfuck 컴파일러는 아마도 명령 시퀀스를 문자열로 수행하고 함수를 반환하기 위해 평가하는 함수를 구성하려고합니다.

구문 분석 기능 (예 : jQuery.parsejson)으로 JSON 구조를 구문 분석하면 JSON 파일의 완벽한 구조 (각 속성 이름은 이중 인용문입니다)를 기대합니다. 그러나 JavaScript는 더 유연합니다. 따라서 Eval ()을 사용하여 피할 수 있습니다.

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