06 julio, 2008

El segundo parámetro del Eval

La semana pasada alguien abrió la Caja de Pandora al descubrir (siempre ha estado ahí) que los navegadores Gecko (como Firefox) admiten un segundo parámetro para indicar en qué ámbito se ejecuta la cadena de código del primer parámetro (el que conocemos todos): eval( string [,scope] );

La particularidad de ese segundo parámetro es que indicando un objeto que hemos creado con clausuras (métodos privados) que considerábamos seguro, de repente es posible ejecutar código que accede a esos métodos e incluso es capaz de sustituirlos. John Resig ofrece más detalles y un ejemplo:

// obteniendo valores privados
var obj = (function() {
  var a = 21;
  return {
    // función pública que debe referenciar a la variable privada 'a'
    fn: function() {a;}
  };
})();

var foo;
eval('foo=a', obj.fn);
console.log(foo); // 21 

Al parecer la documentación de 1998 indica que se incluyó el parámetro para permitir hacer eval sobre otros ámbitos. En aquella época, la seguridad no era precisamente una preocupación. El caso es que en Mozilla visto el revuelo causado, la preocupación de los programadores por su código y los tradicionales ataques al lenguaje que se han incrementado1 han decidido considerarlo un bug y eliminarán el parámetro para el futuro Firefox 3.1.

El otro punto de vista

Hasta aquí la versión más conocida. Pero resulta que Andrea Giammarchi está pidiendo justo lo contrario, que dejen ese parámetro en Firefox y que lo implementen en el resto de navegadores. ¿Se ha vuelto loco? Andrea defiende que gracias a ese bug y a la definición de constantes en Firefox, por fin es posible ejecutar/evaluar código de terceros (no fiable) en un entorno seguro:
const entornoSeguro = function(A, B, D, F, N, O, R, S){
    const   Array   = A,
            Boolean = B,
            Date    = D,
            Function= F,
            Number  = N,
            Object  = O,
            RegExp  = R,
            String  = S,
            eval    = function(String){
                return  self.eval("(" + String + ")");
            };
    return  new function(){};
}(
    Array,
    Boolean,
    Date,
    Function,
    Number,
    Object,
    RegExp,
    String
);

eval("Array=function(){}; alert(Array);", entornoSeguro);
/* function Array(){ [native code] } */
Lo que hace es definir un entorno con los mismos objetos que ya tiene Javascript pero como constantes de forma que al hacer referencia a estos desde el código a ejecutar ya no cabría la posibilidad que existía en Javascript de redefinir un objeto básico (como Array).

Dudo que le hagan caso, pero no deja de sonar interesante su petición. Al fin y al cabo, como el dice, hay problemas de seguridad más grandes por resolver como la inyección de código SQL o XSS. Y ofrece como solución para los más neuróticos: usar las constantes de Firefox para definir un eval sin el conflictivo segundo parámetro:
// webreflection "from the space"
try{eval("const $eval=function(eval){return function($eval){return eval($eval)}}(eval)")}catch($){$eval=eval};

Poder hacer cosas como esta última es lo más apasionante de Javascript.

1: Afortunadamente, esta misma semana a Ruby también le ha salido un serio problema que todavía está pendiente de solución cosa que habrá frenado en parte los ataques de los programadores más dogmáticos contra Javascript.

Publicar un comentario en la entrada

Últimos links en indiza.com