¿Qué constituye el "uso incorrecto" de la función de evaluación de JavaScript? [cerrado]

13

Eval es una característica del lenguaje notoriamente controvertida. Douglas Crockford lo rechaza rotundamente. Me pregunto qué riesgos específicos trae Eval. De acuerdo con esta pregunta Improper use of eval opens up your code for injection attacks,.

¿Cuáles son algunos usos inadecuados del comando Eval y qué agujeros de seguridad abren?

Derek Adair
fuente

Respuestas:

31

Cuando estaba implementando el motor JScript, abogaba por que se imprimieran las camisetas EVAL IS EVIL , pero lamentablemente nunca lo hicimos.

Mi mayor problema con eval no es el obvio ataque de inyección de código malicioso, aunque ciertamente es una gran preocupación. Mi mayor problema es que la gente tiende a usarlo como un martillo realmente grande para resolver problemas realmente pequeños. La mayoría de los usos del mundo real que vi de "eval" en la naturaleza cuando estaba en el equipo de JScript podrían haberse resuelto trivialmente usando una tabla de búsqueda; y dado que cada objeto en JScript ya es una tabla de búsqueda, no es como si fuera una carga onerosa. Eval inicia el compilador nuevamente y destruye completamente la capacidad del compilador para optimizar su código .

Para algunas ideas más en este sentido, vea mis artículos de 2003 sobre el tema:

Maldad general:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx

Inyección ataque maldad:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/04/53335.aspx

Eric Lippert
fuente
¿Qué evalopina sobre la introducción de grandes fragmentos de código de la forma en que les gusta a aplicaciones como JSPacker? JSPacker + gzip generalmente da como resultado tamaños de archivo más pequeños que cualquiera de las soluciones por sí solo, pero como señala correctamente, esencialmente está activando un compilador dos veces en la misma pieza de código, más algo de sobrecarga para hacer reemplazos de cadenas.
Matthew Scharley
2
@Matthew: a menudo hay una compensación entre el espacio y el tiempo, y aprovechar esa compensación a veces puede ser una gran victoria. Si el propósito de la técnica es mejorar el rendimiento, entonces mi opinión es que si una medición cuidadosa muestra que es una victoria significativa en escenarios realistas sin introducir agujeros de seguridad, genial, hazlo. Pero no sé lo suficiente sobre la técnica específica para criticar sus detalles.
Eric Lippert
Deseo una de las respuestas que había visto ya sea aquí o en el propio SO hubiera declarado lo que tu enlace de un segundo estados: que eval()es no un riesgo de seguridad en el código de cliente (navegador).
sq33G
4

La mayoría de los agujeros de seguridad son el mismo tipo de agujeros que con la inyección SQL, es decir, concatenar la entrada del usuario en el código JavaScript. La diferencia es que, si bien hay formas de garantizar que esto no suceda con SQL, no hay mucho que pueda hacer con JavaScript.

Como un ejemplo trivial e inútil, una calculadora JavaScript simplista:

textbox1.value = eval(textbox2.value);

Un ejemplo de uso correcto son algunos de los empaquetadores de JavaScript que comprimen JavaScript al extraer palabras comunes y reemplazarlas con reemplazos cortos de 1-2 caracteres. El empaquetador genera todo esto junto con el código de reemplazo de cadena basado en el diccionario generado y luego evalúa el resultado.

Matthew Scharley
fuente
1

Hay algunas cosas que son imposibles de hacer en JS sin una función eval-como ( eval, Functiony tal vez más).

Toma applypor ejemplo. Es fácil de usar cuando se usa en llamadas a funciones normales:

foo.apply(null, [a, b, c])

Pero, ¿cómo haría esto para los objetos que está creando a través de una nueva sintaxis?

new Foo.apply(null, [a, b, c]) no funciona, ni lo hacen formas similares.

Pero puede evitar esta limitación a través de evalo Function(yo uso Functionen este ejemplo):

Function.prototype.New = (function () {
    var fs = [];
    return function () {
        var f = fs[arguments.length];
        if (f) {
            return f.apply(this, arguments);
        }
        var argStrs = [];
        for (var i = 0; i < arguments.length; ++i) {
            argStrs.push("a[" + i + "]");
        }
        f = new Function("var a=arguments;return new this(" + argStrs.join() + ");");
        if (arguments.length < 100) {
            fs[arguments.length] = f;
        }
        return f.apply(this, arguments);
    };
}) ();

Ejemplo:

Foo.New.apply(null, [a, b, c]);

Por supuesto, puede construir manualmente las funciones que Function.prototype.Newusa, pero no solo es detallado y torpe, sino que (por definición) tiene que ser finito. Functionpermite que el código funcione para cualquier número de argumentos.

Thomas Eding
fuente
2
Es cierto, pero la pregunta del OP fue " ¿Cuáles son algunos usos inadecuados del comando Eval y qué agujeros de seguridad abren? ", No " ¿eval() De qué sirve ? "
Ross Patterson
1
@RossPatterson: Supongo que principalmente miré el título de la pregunta jaja.
Thomas Eding
Aún así, +1 por encontrar un buen uso para una característica de lenguaje incorrecto :-)
Ross Patterson
1

Una respuesta un tanto directa de mi parte fue desarrollar un área de prueba de API orientada al desarrollador. Le dimos un área de texto en una página y un botón Ejecutar. El punto central de la página era que pudieran probar cosas en Javascript contra nuestra API de comunicación de iframe que no era tan fácil de hacer en un entorno local.

Cualquier cosa maliciosa que podría haberse hecho en ese caso también podría haber sido hecha por el desarrollador abriendo sus herramientas F12.

Katana314
fuente
0

Estoy de acuerdo en que rara vez se debe usar, pero he encontrado un caso de uso poderoso para eval.

Hay una nueva característica experimental en Firefox llamada asm.js con la que he estado trabajando. Permite compilar un subconjunto limitado del lenguaje Javascript en código nativo. Sí, esto es muy asombroso, pero tiene limitaciones. Puede pensar en el subconjunto limitado de Javascript como un lenguaje tipo C incrustado en Javascript. Realmente no está destinado a ser leído o escrito por humanos.

Este subconjunto limitado de Javascript no me permite inyectar mi código generado en tiempo de ejecución en el código compilado una vez que se ha compilado.

He escrito un código que permite al usuario escribir, en notación familiar, una expresión matemática y convertirlo sobre la marcha en código asm.js. A menos que quiera que el código sea procesado en el lado del servidor (que no lo hago), evales la única herramienta que me permite tener el código resultante procesado por el navegador en tiempo real.

Galletas De Harina De Arroz
fuente
0

Como lo señalaron otros, lo más importante cuando se trabaja evales mantenerlo a salvo. Para eso, desea hacer una verificación exhaustiva de los argumentos y mantener evalel código simple, ya que generalmente es mucho más difícil mantener y asegurar el código generado en tiempo de ejecución.

Dicho esto, disfruto usarlo evalpara dos tipos de cosas (aunque probablemente haya alternativas mejores y menos malvadas):

  1. Dado que evales una forma de "código de almacenamiento en caché explícito", se puede utilizar para mejorar el rendimiento. Tenga en cuenta que los optimizadores siempre se mejoran, pero simplemente no hay garantía de lo que pueden hacer por usted. Al hacer las cosas explícitas en el código, en realidad puede ayudar al optimizador a tomar decisiones más inteligentes.
  2. También se puede utilizar para ofrecer formas básicas de seguridad de tipos, así como otras características de lenguaje que JS carece, sin deteriorar el rendimiento.

Este enfoque de iterador de objeto precompilado , por ejemplo, muestra claros beneficios de rendimiento cuando se usa evalpara la iteración de propiedad de objeto. También muestra los inicios de un poderoso sistema de tipos que puede proporcionar una comprobación de restricciones implícita y mucho más, a un costo bajo o nulo.

Muchos desarrolladores experimentados de Javascript probablemente señalarían que esto es un agujero de conejo, ya que, si comienzas a escribir Javascript de esta manera, esencialmente cambias la forma en que usas el idioma. Sin embargo, eso podría no ser necesariamente algo malo para quienes disfrutan de Javascript, pero también les faltan características fundamentales del lenguaje que solo se pueden lograr cambiando la forma en que usamos el lenguaje en sí.

Domi
fuente
-3

Tengo una situación en la que eval parece ser el camino a seguir, evaluando una cadena y devolviendo una variable existente cuyo nombre es el mismo que la cadena.

Tengo varias tablas: table1ResultsTable, table2ResultsTable, tableNResultsTable. Tengo variables configuradas con los mismos nombres, que son objetos de tabla de datos jQuery. Los uso para configurar las tablas y llamar a las funciones de tabla de datos de jQuery en ellas.

Cada tabla tiene asignada class = "resultsTable". Ahora, necesito obtener la variable cuando se hace clic en la tabla. Estoy haciendo esto:

$('resultsTable).on('click', 'td', function(event) {
    var cResultsTable = eval(event.target.parentElement.parentElement.parentElement.id);
    [etc]
});

Así que obtengo el ID de la tabla en la que se hizo clic en la celda, que tiene el mismo nombre que la variable de objeto de tabla de datos correspondiente. Si alguien tiene una sugerencia para una mejora, me gustaría saberlo.

BobRodes
fuente
1
¿Por qué necesitas evaluar? La identificación debe ser una cadena simple, no un código. De todos modos, event.target.parentElement.parentElement.parentElementes horrible. Además, esperaría que la llamada de evaluación genere un error de "error de referencia: [id] no está definido", a menos que esté usando deliberadamente identificables evaluables (que están rotos, incorrectos y pueden causar que ocurran cosas extrañas si finaliza hasta generar identificadores duplicados).
Brian
Quizás no me estoy aclarando. La identificación ES una cadena simple. Es la identificación de la tabla en la que se ha hecho clic. También tengo una variable de objeto (establecida con el método jQuery datatable (), que hace referencia a la misma tabla) con el mismo nombre que el id. Estoy tratando de obtener esa variable, para acceder a sus funciones (de hecho, para agregar la clase "row_selected" a la fila seleccionada), cuando se hace clic en la tabla. Sin embargo, desde que escribí esto, he encontrado una mejora. Solo pongo todas las referencias de objetos en una matriz, nombro los elementos de la misma manera que la identificación y conecto la cadena de identificación para obtener el objeto ref.
BobRodes
Brian, si tienes un mejor medio para encontrar la identificación de la tabla en la que se ha hecho clic, soy todo oídos. Para la función de tablas de datos, necesito manejar el evento click en la celda y agregar la clase row_selected a su parentNode. No sé por qué no puedo manejar el evento de fila y agregarle la clase directamente, pero la fila no se muestra como seleccionada cuando hago eso.
BobRodes
1
Quizás no me estoy aclarando. Si llama a eval en una cadena simple (es decir, no JS), lanzará una excepción. Por lo tanto, su uso de eval no tiene sentido. Si está generando una variable de objeto con el mismo nombre que la identificación, su código funcionará ... pero me parece que no funciona. Prefiero crear la variable usando document.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE(por no decir que es genial tampoco, pero es mejor que eval). Como señala Eric Lippert, "cada objeto en JScript ya es una tabla de búsqueda".
Brian
Ok, ¿entonces estás diciendo agregar una propiedad a la referencia del elemento y establecerla en la referencia del objeto de tabla de datos? Eso también me suena más apretado.
BobRodes