¿Cuándo la evaluación () de JavaScript no es mala?
Estoy escribiendo código JavaScript para analizar funciones ingresadas por el usuario (para una funcionalidad similar a una hoja de cálculo). Habiendo analizado la fórmula, pude convertirla a JavaScript y ejecutarla eval()
para obtener el resultado.
Sin embargo, siempre he evitado usarlo eval()
si puedo evitarlo porque es malo (y, con razón o sin ella, siempre he pensado que es aún más malo en JavaScript, porque el usuario puede cambiar el código a evaluar). ).
Entonces, ¿cuándo está bien usarlo?
Me gustaría tomarme un momento para abordar la premisa de su pregunta: que eval() es " malo ". La palabra " malvado ", tal como la usan los lenguajes de programación, generalmente significa "peligroso", o más precisamente "capaz de causar mucho daño con una orden aparentemente simple". Entonces, ¿cuándo está bien utilizar algo peligroso? Cuando sabes cuál es el peligro y cuando estás tomando las precauciones adecuadas.
Al grano, veamos los peligros en el uso de eval(). Probablemente haya muchos pequeños peligros ocultos como todo lo demás, pero los dos grandes riesgos (la razón por la que eval() se considera malo) son el rendimiento y la inyección de código.
- Rendimiento: eval() ejecuta el intérprete/compilador. Si su código está compilado, entonces esto es un gran éxito, porque necesita llamar a un compilador posiblemente pesado en medio del tiempo de ejecución. Sin embargo, JavaScript sigue siendo principalmente un lenguaje interpretado, lo que significa que llamar a eval() no supone un gran impacto en el rendimiento en el caso general (pero consulte mis comentarios específicos a continuación).
- Inyección de código: eval() potencialmente ejecuta una cadena de código con privilegios elevados. Por ejemplo, un programa que se ejecuta como administrador/root nunca querría evaluar() la entrada del usuario, porque esa entrada podría ser "rm -rf /etc/important-file" o algo peor. Nuevamente, JavaScript en un navegador no tiene ese problema, porque el programa se ejecuta de todos modos en la propia cuenta del usuario. JavaScript del lado del servidor podría tener ese problema.
Pasemos a tu caso concreto. Por lo que tengo entendido, usted mismo está generando las cadenas, por lo que suponiendo que tenga cuidado de no permitir que se genere una cadena como "rm -rf algo-importante", no hay riesgo de inyección de código (pero recuerde, es muy, muy difícil asegurar esto en el caso general). Además, si lo está ejecutando en el navegador, creo que la inyección de código es un riesgo bastante menor.
En cuanto al rendimiento, tendrás que compararlo con la facilidad de codificación. En mi opinión, si está analizando la fórmula, también podría calcular el resultado durante el análisis en lugar de ejecutar otro analizador (el que está dentro de eval()). Pero puede ser más fácil codificar usando eval(), y el impacto en el rendimiento probablemente será imperceptible. Parece que eval() en este caso no es más malo que cualquier otra función que pueda ahorrarle algo de tiempo.
eval()
no es malo. O, si lo es, es malo de la misma manera que la reflexión, la E/S de archivos/redes, los subprocesos y el IPC son "malos" en otros lenguajes.
Si, para su propósito , eval()
es más rápido que la interpretación manual, o hace que su código sea más simple o más claro... entonces debería usarlo. Si ninguna de las dos cosas, entonces no deberías hacerlo. Simple como eso.
Consigamos gente real:
Cada navegador importante ahora tiene una consola incorporada que su posible hacker puede usar con abundancia para invocar cualquier función con cualquier valor. ¿Por qué se molestarían en usar una declaración eval, incluso si pudieran?
Si se necesitan 0,2 segundos para compilar 2000 líneas de JavaScript, ¿cuál es la degradación de mi rendimiento si evalúo cuatro líneas de JSON?
Incluso la explicación de Crockford de que "la evaluación es mala" es débil.
eval es malvado. La función eval es la característica más utilizada de JavaScript. evítalo
Como diría el propio Crockford: "Este tipo de afirmaciones tienden a generar neurosis irracionales. No las crean".
Comprender la evaluación y saber cuándo podría resultar útil es mucho más importante. Por ejemplo, eval es una herramienta sensata para evaluar las respuestas del servidor generadas por su software.
Por cierto: Prototype.js llama a eval directamente cinco veces (incluso en evalJSON() y evalResponse()). jQuery lo usa en parseJSON (a través del constructor de funciones).
Tiendo a seguir el consejo de Crockfordeval()
y a evitarlo por completo. Incluso las formas que parecen requerirlo no lo requieren. Por ejemplo, le setTimeout()
permite pasar una función en lugar de eval.
setTimeout(function() {
alert('hi');
}, 1000);
Incluso si es una fuente confiable , no la uso, porque el código devuelto por JSON podría estar confuso, lo que en el mejor de los casos podría hacer algo extraño y, en el peor, exponer algo malo.
Eval es complementario a la compilación que se utiliza para crear plantillas para el código. Por creación de plantillas quiero decir que escribes un generador de plantillas simplificado que genera código de plantilla útil que aumenta la velocidad de desarrollo.
He escrito un marco, donde los desarrolladores no usan EVAL, pero usan nuestro marco y, a su vez, ese marco tiene que usar EVAL para generar plantillas.
El rendimiento de EVAL se puede aumentar utilizando el siguiente método; en lugar de ejecutar el script, debes devolver una función.
var a = eval("3 + 5");
Se debe organizar como
var f = eval("(function(a,b) { return a + b; })");
var a = f(3,5);
El almacenamiento en caché de f sin duda mejorará la velocidad.
Además, Chrome permite la depuración de dichas funciones con mucha facilidad.
En cuanto a la seguridad, usar eval o no apenas hará ninguna diferencia,
- En primer lugar, el navegador invoca el script completo en un entorno limitado.
- Cualquier código que sea malo en EVAL, es malo en el propio navegador. El atacante o cualquier persona puede inyectar fácilmente un nodo de script en DOM y hacer cualquier cosa si puede evaluar algo. No utilizar EVAL no hará ninguna diferencia.
- Lo que resulta perjudicial es principalmente una mala seguridad del lado del servidor. La mala validación de las cookies o la mala implementación de la ACL en el servidor provocan la mayoría de los ataques.
- Había una vulnerabilidad reciente de Java, etc., en el código nativo de Java. JavaScript fue y está diseñado para ejecutarse en un entorno limitado, mientras que los subprogramas fueron diseñados para ejecutarse fuera de un entorno limitado con certificados, etc., lo que genera vulnerabilidades y muchas otras cosas.
- Escribir código para imitar un navegador no es difícil. Todo lo que tienes que hacer es realizar una solicitud HTTP al servidor con tu cadena de agente de usuario favorita. Todas las herramientas de prueba se burlan de los navegadores de todos modos; Si un atacante quiere hacerte daño, EVAL es su último recurso. Tienen muchas otras formas de lidiar con la seguridad del lado del servidor.
- El navegador DOM no tiene acceso a archivos ni a un nombre de usuario. De hecho, no hay nada en la máquina al que eval pueda dar acceso.
Si la seguridad de su servidor es lo suficientemente sólida como para que cualquiera pueda atacar desde cualquier lugar, no debe preocuparse por EVAL. Como mencioné, si EVAL no existiera, los atacantes tendrían muchas herramientas para hackear su servidor independientemente de la capacidad EVAL de su navegador.
Eval solo sirve para generar algunas plantillas para realizar un procesamiento de cadenas complejo basado en algo que no se usa de antemano. Por ejemplo, preferiría
"FirstName + ' ' + LastName"
Opuesto a
"LastName + ' ' + FirstName"
Como mi nombre para mostrar, que puede provenir de una base de datos y que no está codificado.