8

背景: 私は、特定のサイトに使用されるフレームワーク/ライブラリに、グリースモンキー/ユーザー スクリプトと連携して取り組んでいます。このフレームワーク/ライブラリにより、アドオンのサポートが可能になります。それが機能する方法は、必要なページ、リソース、ectera をリストするライブラリにアドオンを登録することです。ライブラリは、アドオンのload()関数を呼び出すためにすべての条件が満たされるまで待機します。

問題: この「必要なもの」のリストでは、アドオン開発者が「必要なリソース」として評価される javascript (文字列として) を指定できるようにしたいと考えています。たとえば'document.getElementById("banana")'。私がやりたいのは、「必要なリソース」の評価をセミサンドボックス化して、評価がウィンドウとDOMオブジェクトにアクセスできるようにすることですが、それらを直接変更することはできません。また、サンドボックスから eval と evalJS にアクセスできないようにしたいと思います。


:

  • document.getElementById("banana")->有効
  • document.getElementById("apple).id = "orange"-> 無効
  • window.grape->有効
  • window.grape = 'potato'-> 無効
  • (someObj.applesCount > 0 ? 'some' : 'none')->有効


私がこれまでに持っているもの

function safeEval(input) {

    // Remove eval and evalJS from the window:
    var e = [window.eval, window.evalJS], a;
    window.eval = function(){};
    window.evalJS = function(){};

    try {

        /* More sanition needed before being passed to eval */

        // Eval the input, stuffed into an annonomous function
        // so the code to be evalued can not access the stored
        // eval functions:
        a = (e[0])("(function(){return "+input+"}())");
    } catch(ex){}

    // Return eval and evalJS to the window:
    window.eval = e[0];
    window.evalJS = e[1];

    // Return the eval'd result
    return a;
}


:
これは Greasemonkey/userscript です。サイトを変更するための直接アクセス権がないか、JavaScript です。
の入力はsafeEval()、ウィンドウ オブジェクトまたは DOM を変更しない限り、DOM クエリまたは単純な評価など、任意の有効な JavaScript にすることができます。

4

4 に答える 4

7

There's no absolute way to prevent an end user or addon developer from executing specific code in JavaScript. That's why security measures in an open source language like JavaScript is said to be foolproof (as in it's only effective against fools).

That being said however let's build a sandbox security layer to prevent inexperienced developers from breaking your site. Personally I prefer using the Function constructor over eval to execute user code for the following reasons:

  1. The code is wrapped in an anonymous function. Hence it may be stored in a variable and called as many times as needed.
  2. The function always exists in the global scope. Hence it doesn't have access to the local variables in the block which created the function.
  3. The function may be passed arbitrary named parameters. Hence you may exploit this feature to pass or import modules required by the user code (e.g. jQuery).
  4. Most importantly you may set a custom this pointer and create local variables named window and document to prevent access to the global scope and the DOM. This allows you to create your own version of the DOM and pass it to the user code.

Note however that even this pattern has disadvantages. Most importantly it may only prevent direct access to the global scope. User code may still create global variables by simply declaring variables without var, and malicious code may use hacks like creating a function and using it's this pointer to access the global scope (the default behavior of JavaScript).

So let's look at some code: http://jsfiddle.net/C3Kw7/

于 2012-09-23T17:54:05.583 に答える
0

あなたはこのようなことをすることができます:http://jsfiddle.net/g68NP/

問題は、すべてのプロパティ、すべてのネイティブメソッドなどを保護するために、多くのコードを追加する必要があることです。コードの本質は__defineGetter__、サポートが制限されているを使用することになります。IEでこれを実行していない可能性があるため、問題ないはずです。

編集: http: //jsfiddle.net/g68NP/1/ このコードは、すべてのプロパティを読み取り専用にします。の使用はhasOwnProperty()望ましい場合と望ましくない場合があります。

JSFiddleがダウンした場合:

function safeEval(input) {
    // Remove eval and evalJS from the window:
    var e = [window.eval, window.evalJS, document.getElementById], a;
    window.eval = function(){};
    window.evalJS = function(){};
    document.getElementById = function (id) {
        var elem = (e[2]).call(document, id);
        for (var prop in elem) {
            if (elem.hasOwnProperty(prop)) {
                elem.__defineGetter__(prop, function () {
                    return (function (val) {
                        return val;
                    }(elem[prop]));
                });
            }                
        }
        return elem;
    };

    try {
        /* More sanition needed before being passed to eval */

        // Eval the input, stuffed into an annonomous function
        // so the code to be evalued can not access the stored
        // eval functions:
        a = (e[0])("(function(){return " + input + "}())");
    } catch(ex){}

    // Return eval and evalJS to the window:
    window.eval = e[0];
    window.evalJS = e[1];
    document.getElementById = e[2];

    // Return the eval'd result
    return a;
}
于 2012-09-23T17:16:33.413 に答える
0

単純な getter だけが必要な場合は、何かを評価しようとするのではなく、1 つをプログラムします。

function get(input) {
    // if input is a string, it will be used as a DOM selector
    // if it is an array (of strings), they will access properties of the global object
    if (typeof input == "string")
        return document.querySelector(input);
    else if (Array.isArray(input)) {
        var res = window;
        for (var i=0; i<input.length && typeof input[i] == "string" && res; i++)
            res = res[input[i]];
        return res;
    }
    return null;
}
于 2012-09-23T16:51:53.230 に答える