35

eval() する必要がある JavaScript フラグメントを含む可能性のある別のファイルを読み取る JavaScript ファイルがあります。スクリプト フラグメントは、実行できることと変更できる変数を制限する JavaScript の厳密なサブセットに準拠することになっていますが、eval がグローバル スコープ内の変数を認識しないようにすることで、これを強制する方法があるかどうかを知りたいです。 . 次のようなもの:

function safeEval( fragment )
{
    var localVariable = g_Variable;

    {
        // do magic scoping here so that the eval fragment can see localVariable
        // but not g_Variable or anything else outside function scope

        eval( fragment );
    }
}

実際のコードはこのようにする必要はありません。私はクロージャなどを使ったあらゆる奇妙なトリックを受け入れます。しかし、これが可能かどうかを知りたいです。

4

9 に答える 9

57

簡単な答え: いいえ。グローバル スコープ内にある場合は、何にでも使用できます。

長い答え:実行環境を本当に読み取ったり、いじったりしたいeval()信頼できないコードを実行している場合は、めちゃくちゃです。しかし、ed されるものを含め、実行されるすべてのコードを所有し、信頼している場合は、実行コンテキストをオーバーライドすることでそれを偽造することができます。eval()

function maskedEval(scr)
{
    // set up an object to serve as the context for the code
    // being evaluated. 
    var mask = {};
    // mask global properties 
    for (p in this)
        mask[p] = undefined;

    // execute script in private context
    (new Function( "with(this) { " + scr + "}")).call(mask);
}

繰り返しますが、次のことを強調しなければなりません。

これは、信頼されたコードが実行されるコンテキストから保護するためにのみ機能します。コードを信頼しない場合は、使用しないeval()でください (または、 new に渡すかFunction()、 のように動作する他の方法で使用してeval()ください)。

于 2009-02-12T22:39:15.140 に答える
6

上記のブロック アプローチでの動的関数ラッピング スクリプトと同様にwith、これにより、実行するコードに疑似グローバルを追加できます。特定のものをコンテキストに追加することで、特定のものを「隠す」ことができます。

function evalInContext(source, context) {
    source = '(function(' + Object.keys(context).join(', ') + ') {' + source + '})';

    var compiled = eval(source);

    return compiled.apply(context, values());

    // you likely don't need this - use underscore, jQuery, etc
    function values() {
        var result = [];
        for (var property in context)
            if (context.hasOwnProperty(property))
                result.push(context[property]);
        return result;
    }
}

例については、 http://jsfiddle.net/PRh8t/を参照してください。Object.keysすべてのブラウザーでサポートされているわけではないことに注意してください。

于 2014-05-25T05:27:06.250 に答える
3

eval の範囲を制限することはできません

ところで、この投稿を参照してください

物事の壮大な計画で達成したいことを達成するための他の方法があるかもしれませんが、決して eval の範囲を制限することはできません。特定の変数を JavaScript で疑似プライベート変数として非表示にできる場合がありますが、これが目的だとは思いません。

于 2009-02-12T21:56:51.217 に答える
3

これがアイデアです。静的アナライザー (たとえば、 esprima で作成できるもの) を使用して、eval されたコードが使用する外部変数を特定し、それらにエイリアスを設定した場合はどうなるでしょうか。「外部コード」とは、評価されたコードが使用するが宣言しない変数を意味します。次に例を示します。

eval(safeEval(
     "var x = window.theX;"
    +"y = Math.random();"
    +"eval('window.z = 500;');"))

ここで、safeEval は、外部変数へのアクセスをブロックするコンテキストで変更された JavaScript 文字列を返します。

";(function(y, Math, window) {"
  +"var x = window.theX;"
  +"y = Math.random();"
  +"eval(safeEval('window.z = 500;');"
"})();"

これでできることがいくつかあります。

  • eval されたコードが外部変数の値を読み取ったり、それらに書き込んだりできないようにすることができます (undefined関数の引数として渡すか、引数を渡さないことにより)。または、変数が安全にアクセスされていない場合に、単に例外をスローすることもできます。
  • また、eval によって作成された変数が周囲のスコープに影響を与えないようにします。
  • 関数パラメーターとしてではなく、クロージャーの外側でこれらの変数を宣言することにより、eval が周囲のスコープで変数を作成できるようにすることができます。
  • 外部変数の値をコピーし、それらを関数への引数として使用することで、読み取り専用アクセスを許可できます
  • safeEval にそれらの特定の名前をエイリアスしないように指示することで、特定の変数への読み取り/書き込みアクセスを許可できます。
  • eval が特定の変数を変更しないケースを検出し、エイリアスから自動的に除外できるようにすることができます (例: この場合、Math は変更されていません)。
  • 周囲のコンテキストとは異なる可能性のある引数値を渡すことにより、実行するコンテキストを eval に与えることができます
  • 関数から関数の引数も返すことでコンテキストの変更をキャプチャできるため、eval の外部でそれらを調べることができます。

の使用は特殊なケースであることに注意してください。これはeval、その性質上、別の関数で効果的にラップすることができないためです (これが、 を実行する必要がある理由ですeval(safeEval(...)))。

もちろん、この作業をすべて実行するとコードが遅くなる可能性がありますが、ヒットが問題にならない場所も確かにあります。これが誰かに役立つことを願っています。また、誰かが概念実証を作成した場合は、ここにリンクを表示したいと思います。)

于 2013-08-11T20:44:16.037 に答える
2

信頼できないコードを実行しないでください。グローバルは常にアクセス可能です。コードを信頼できる場合は、次のようにスコープ内の特定の変数を使用してコードを実行できます。

(new Function("a", "b", "alert(a + b);"))(1, 2);

これは次と同等です。

(function (a, b) {
    alert(a + b);
})(1, 2);
于 2015-02-07T00:49:02.803 に答える
2

使用しないでくださいeval。別の方法がありますjs.js: JS で書かれた JS インタープリター。これにより、セットアップに成功した任意の環境で JS プログラムを実行できます。プロジェクト ページの API の例を次に示します。

var jsObjs = JSJS.Init();
var rval = JSJS.EvaluateScript(jsObjs.cx, jsObjs.glob, "1 + 1");
var d = JSJS.ValueToNumber(jsObjs.cx, rval);
window.alert(d); // 2
JSJS.End(jsObjs);

ご覧のとおり、怖いものは何もありません。

于 2013-11-18T14:14:10.960 に答える