2009-02-12 24 views
29

Tengo un archivo javascript que lee otro archivo que puede contener fragmentos de JavaScript que deben ser evaluados() - ed. Se supone que los fragmentos de script se ajustan a un subconjunto estricto de javascript que limita lo que pueden hacer y las variables que pueden cambiar, pero quiero saber si hay alguna forma de aplicar esto al evitar que eval evalúe variables en el ámbito global. . Algo así como lo siguiente:Restringir eval() a un ámbito estrecho

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); 
    } 
} 

El código real no tiene que parecerse a esto - Estoy abierto a cualquier y todos los trucos extraños con cierres, etc. Pero quiero saber si esto es aún posible.

+0

no sé si va a trabajar para 'eval' pero se puede tratar de conmutador su contexto de ejecución (objeto de activación de google). – jfs

+0

Eche un vistazo a la implementación de dojox.secure.sandbox. – jfs

+0

Ahora, lo que probablemente quiera es un trabajador web. – bjb568

Respuesta

50

Respuesta corta: No. Si está en el alcance global, está disponible para cualquier cosa.

Respuesta larga: si estás eval() ing código no confiable que realmente quiere leer o meterse con su entorno de ejecución, estás jodido. Pero si usted es dueño y confiar en que todo el código que se está ejecutando, incluyendo que el ser que eval() ed, que se puede fingir reemplazando el contexto de ejecución:

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); 
} 

Una vez más, debo hacer hincapié en:

Esto sólo servirá para proteger de confianza código del contexto en el que se ejecuta. Si no confía en el código, NO LO HAGA eval() (o páselo al nuevo Function(), o úselo de otra manera que se comporte como eval()).

+0

Hay un pequeño problema con el enfoque 'con 'que me ha mordido antes. Las funciones declaradas dentro del bloque con no tienen acceso al destino de la instrucción with. –

+0

Sí, espero que una declaración de * función * pueda ser "levantada" en ese caso; querrá apegarse a las expresiones. – Shog9

+0

maldición .... no puedo decir lo feliz que estoy: D esto es increíble! ahora puedo completar mi plantilla de motor ... tengo que probar más, pero creo que ya tengo todo ... maldición ... eso es genial hombre ... ya sabes ... analizar expresiones cargadas desde la plantilla era difícil , pero con esto es bastante fácil: D ¿Conoces alguna filtración de seguridad? Nunca supe esto "con (esto)" ... sé que tengo que revisar vor keaywords, para eliminar la inyección malvada: D – Mephiztopheles

2

Usted no puede limitar el alcance de eval

ver por cierto this post

Puede haber alguna otra manera de lograr lo que se desea lograr en el gran esquema de las cosas pero no se puede limitar el alcance de eval de cualquier manera. Es posible que pueda ocultar ciertas variables como variables pseudo privadas en JavaScript, pero no creo que esto sea lo que está buscando.

2

Aquí hay una idea. ¿Qué sucede si utiliza un analizador estático (algo que podría compilar con esprima, por ejemplo) para determinar qué variables externas usa el código evaluado, y alias ellos? Por "código externo" quiero decir variables el código evaluado usa pero no declara.He aquí un ejemplo:

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

donde safeEval devuelve la cadena JavaScript modificado con un contexto que bloquea el acceso a variables externas:

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

Hay un par de cosas que puede hacer ahora con esta:

  • Puede asegurarse de que el código evaluado no pueda leer los valores de las variables externas, ni escribir en ellos (pasando undefined como los argumentos de la función, o no pasando argumentos). O simplemente podría lanzar una excepción en los casos donde las variables están siendo accesadas de manera insegura.
  • También aseguran que las variables creadas por eval no afectan el alcance que rodea
  • Se podría permitir que eval para crear variables en el perímetro que rodea al declarar estas variables fuera del cierre en lugar de en función de los parámetros
  • Usted podría permitir acceso de sólo lectura por copia valores de las variables externas y usarlos como argumentos a la función
  • Se podría permitir lectura-escritura a variables específicas contando safeEval a no ser alias de esos nombres particulares
  • puede detectar los casos en que el eval hace not modificar una variable particular y permitir que se excluya automáticamente de ser un alias (por ejemplo. Matemáticas, en este caso, no está siendo modificada)
  • Se podría dar el eval un contexto en el que se ejecutará, mediante introducción de valores de los argumentos que pueden ser diferente que el contexto que rodea
  • Usted podría captar los cambios de contexto también devolviendo los argumentos de función de la función para que pueda examinarlos fuera de la evaluación.

Tenga en cuenta que el uso de eval es un caso especial, ya que por su naturaleza, en la práctica no puede ser envuelto en otra función (por lo que tenemos que hacer eval(safeEval(...))).

Por supuesto, hacer todo este trabajo puede ralentizar su código, pero ciertamente hay lugares donde el golpe no tendrá importancia. Espero que esto ayude a alguien. Y si alguien crea una prueba de concepto, me gustaría ver un enlace aquí;)

1

No utilice eval. Existe una alternativa, js.js: JS interpreter written in JS, para que pueda ejecutar programas JS en cualquier entorno que haya podido configurar. Aquí hay un ejemplo de su API desde la página del proyecto:

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); 

Nada de miedo, como puede ver.

+0

3MB y solo 594 KB después de compresión gzip – prototype

+0

@ user645715 1) Intente utilizar el Compilador de cierre para comprimirlo aún más. 2) Hay una ralentización de 200x, que es mucho peor que el código fuente de 3MB. 3) Todavía no hay otra solución. –

1

Similar a la secuencia de comandos de envoltura de función dinámica en un enfoque de bloque with anterior, esto le permite agregar pseudoglobales al código que desea ejecutar. Puede "ocultar" cosas específicas al agregarlas al contexto.

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; 
    } 
} 

Ver http://jsfiddle.net/PRh8t/ para un ejemplo. Tenga en cuenta que Object.keys no es compatible con todos los navegadores.

0

No ejecute código en el que no confíe. Globals siempre será accesible. Si lo hace confiar en el código, puede ejecutar con variables particulares en su ámbito de aplicación de la siguiente manera:

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

esto es equivalente a:

(function (a, b) { 
    alert(a + b); 
})(1, 2); 
0

respuesta 's Shog9 ♦ es grande. Pero si su código es solo una expresión, el código se ejecutará y no se devolverá nada. Para las expresiones, utilice

function evalInContext(context, js) { 

    return eval('with(context) { ' + js + ' }'); 

} 

Aquí es cómo usarlo:

var obj = {key: true}; 

evalInContext(obj, 'key ? "YES" : "NO"'); 

Se volverá "YES".

Si no está seguro de si el código a ser ejecutado es expresiones o manifestaciones, se pueden combinar:

function evalInContext(context, js) { 

    var value; 

    try { 
    // for expressions 
    value = eval('with(context) { ' + js + ' }'); 
    } catch (e) { 
    if (e instanceof SyntaxError) { 
     try { 
     // for statements 
     value = (new Function('with(this) { ' + js + ' }')).call(context); 
     } catch (e) {} 
    } 
    } 

    return value; 
} 
Cuestiones relacionadas