Pregunta ¿Cuándo es eval evil en php?


En todos los años que he estado desarrollando en php, siempre escuché que usar eval() es malvado

Teniendo en cuenta el siguiente código, ¿no tendría sentido utilizar la segunda opción (y más elegante)? Si no, ¿por qué?

// $type is the result of an SQL statement
// e.g. SHOW COLUMNS FROM a_table LIKE 'a_column';
// hence you can be pretty sure about the consistency
// of your string
$type = "enum('a','b','c')";

// possibility one
$type_1 = preg_replace('#^enum\s*\(\s*\'|\'\s*\)\s*$#', '', $type);
$result = preg_split('#\'\s*,\s*\'#', $type_1);

// possibility two
eval('$result = '.preg_replace('#^enum#','array', $type).';');

73
2018-06-04 15:43


origen


Respuestas:


Sería cauteloso al llamar a eval () puro mal. La evaluación dinámica es una herramienta poderosa y a veces puede ser un salvavidas. Con eval () uno puede solucionar las deficiencias de PHP (ver a continuación).

Los principales problemas con eval () son:

  • Potencial entrada insegura. Pasar un parámetro que no es de confianza es una forma de error. A menudo no es una tarea trivial asegurarse de que un parámetro (o parte de él) sea totalmente confiable.
  • Trickiness. El uso de eval () hace que el código sea inteligente, por lo tanto, más difícil de seguir. Para citar a Brian Kernighan "La depuración es el doble de difícil que escribir el código en primer lugar. Por lo tanto, si escribe el código de la manera más inteligente posible, por definición, no es lo suficientemente inteligente como para depurarlo"

El problema principal con el uso real de eval () es solo uno:

  • Desarrolladores inexpertos que lo usan sin suficiente consideración.

Como regla general, tiendo a seguir esto:

  1. A veces eval () es la única / la solución correcta.
  2. Para la mayoría de los casos, uno debe probar algo más.
  3. Si no está seguro, vaya a 2.
  4. Más, sé muy, muy cuidadoso.

118
2018-06-04 17:08



eval es malo cuando solo hay la más mínima posibilidad de que la entrada de usuario esté incluida en la cadena evaluada. Cuando evalúa sin contenido que proviene de un usuario, debe estar seguro.

Sin embargo, debe pensar al menos dos veces antes de usar eval, parece engañosamente simple, pero con el manejo de errores (vea el comentario de VBAssassins), depuración, etc. en mente, ya no es tan simple.

Entonces, como regla general: Olvídalo. ¡Cuando eval es la respuesta, estás formulando la pregunta equivocada! ;-)


37
2018-06-04 15:47



eval () es igualmente malvado en todo momento.

"¿Cuándo eval () no es malo?" En mi opinión, es la pregunta equivocada, porque parece implicar que los inconvenientes del uso de eval () desaparecen mágicamente en algunos contextos.

Usar eval () generalmente es una mala idea porque disminuye la legibilidad del código, la capacidad de predecir la ruta del código (y las posibles implicaciones de seguridad) antes del tiempo de ejecución y, por lo tanto, la capacidad de depurar el código. El uso de eval () también puede evitar que el código evaluado y el código que lo rodea sean optimizados por un caché de opcode como el Zend Opcache integrado en PHP 5.5 y superior, o por un compilador JIT como el de HHVM.

Además, no hay ninguna situación para la cual sea absolutamente necesario usar eval () - PHP es un lenguaje de programación totalmente funcional sin él.

Si usted realmente ve estos como males o si puede justificar personalmente el uso de eval () en algunos casos depende de usted. Para algunos, los males son demasiado grandes como para justificarlo alguna vez, y para otros, eval () es un atajo práctico.

Sin embargo, si ves eval () como malvado, es malvado en todo momento. No pierde mágicamente su maldad según el contexto.


17
2018-06-05 01:36



En este caso, eval es probablemente lo suficientemente seguro, siempre que nunca sea posible crear columnas arbitrarias en una tabla por un usuario.

Sin embargo, en realidad no es más elegante. Esto es básicamente un problema de análisis de texto, y abusar del analizador de PHP para manejarlo parece un poco hacky. Si quieres abusar de las características del lenguaje, ¿por qué no abusar del analizador JSON? Al menos con el analizador JSON, no hay posibilidad de inyección de código.

$json = str_replace(array(
    'enum', '(', ')', "'"), array)
    '',     '[', ']', "'"), $type);
$result = json_decode($json);

Una expresión regular es probablemente la forma más obvia. Puede usar una sola expresión regular para extraer todos los valores de esta cadena:

$extract_regex = '/
    (?<=,|enum\()   # Match strings that follow either a comma, or the string "enum("...
    \'      # ...then the opening quote mark...
    (.*?)       # ...and capture anything...
    \'      # ...up to the closing quote mark...
    /x';
preg_match_all($extract_regex, $type, $matches);
$result = $matches[1];

14
2018-06-04 16:21



Cuando está utilizando datos externos (como la entrada del usuario) dentro de la evaluación.

En su ejemplo anterior, esto no es un problema.


11
2018-06-04 15:46



eval() es lento, pero yo no lo llamaría malvado

Es el mal uso que hacemos de eso que puede conducir a código de inyección y sé malo.

Un simple ejemplo:

$_GET = 'echo 5 + 5 * 2;';
eval($_GET); // 15

Un ejemplo dañino:

$_GET = 'system("reboot");';
eval($_GET); // oops

Yo te aconsejaría que no uses eval() pero si lo hace, asegúrese de validar / incluir toda la información en la lista blanca.


8
2018-01-14 02:36



Robaré descaradamente el contenido aquí:

  1. Evaluar por su naturaleza siempre será un problema de seguridad.

  2. Además de las preocupaciones de seguridad, eval también tiene el problema de ser increíblemente lento. En mis pruebas en PHP 4.3.10 su código 10 veces más lento que el normal y 28 veces más lento en PHP 5.1 beta1.

blog.joshuaeichorn.com: using-eval-in-php


7
2018-06-04 16:51



Personalmente, creo que el código sigue siendo bastante malo porque no estás comentando lo que está haciendo. Tampoco está probando sus entradas para su validez, por lo que es muy frágil.

También creo que, dado que el 95% (o más) de los usos de eval son activamente peligrosos, el pequeño ahorro potencial de tiempo que podría proporcionar en otros casos no vale la pena caer en la mala práctica de usarlo. Además, luego tendrá que explicarles a sus subordinados por qué su uso de eval es bueno y el suyo malo.

Y, por supuesto, tu PHP termina luciendo como Perl;)

Hay dos problemas clave con eval (), (como un escenario de "ataque de inyección"):

1) Puede causar daño 2) Simplemente puede bloquearse

y uno que es más social que técnico:

3) Tendrá la tentación de usarlo inapropiadamente como atajo en otro lugar

En el primer caso, corre el riesgo (obviamente, no cuando está evaluando una cadena conocida) de ejecución de código arbitrario. Sin embargo, sus datos de entrada pueden no ser tan conocidos o tan fijos como cree.

Lo más probable es que (en este caso) se bloquee, y la cadena terminará con un mensaje de error innecesariamente oscuro. En mi humilde opinión, todo el código debe fallar tan limpiamente como sea posible, en su defecto debe arrojar una excepción (como la forma más manejable de error).

Sugeriría que, en este ejemplo, esté codificando por coincidencia en lugar de codificar el comportamiento. Sí, la instrucción enum de SQL (¿y está seguro de que la enum del campo? ¿Llamó al campo derecho de la tabla correcta de la versión correcta de la base de datos? ¿Respondió realmente?) Parece una sintaxis de declaración de matriz en PHP, pero sugiero que lo que realmente quieres hacer es no encontrar la ruta más corta de entrada a salida, sino más bien abordar la tarea especificada:

  • Identifica que tienes una enumeración
  • Extrae la lista interna
  • Desempaquetar los valores de la lista

Cuál es más o menos lo que hace su opción, pero envolvería algunos si y comentarios para mayor claridad y seguridad (por ejemplo, si la primera coincidencia no coincide, arroje una excepción o establezca un resultado nulo).

Todavía hay algunos problemas posibles con las comas o comillas que se han escapado, y probablemente debería descomprimir los datos y luego eliminarlos, pero al menos tratar los datos como datos, en lugar de como código.

Con la versión preg, es probable que su peor resultado sea $ result = null, con la versión eval se desconoce lo peor, pero al menos un crash.


5
2018-06-04 16:19



También le prestaré atención a las personas que mantienen su código.

eval () no es fácil de ver y sabe lo que se supone que debe suceder, tu ejemplo no es tan malo, pero en otros lugares puede ser una pesadilla correcta.


4
2018-06-04 16:00



eval evalúa una cadena como código, el problema es que si la cadena está "contaminada" podría exponer grandes amenazas de seguridad. Normalmente el problema es en un caso donde la entrada del usuario se evalúa en la cadena, en muchos casos el usuario podría ingresar código (php o ssi por ejemplo) que luego se ejecuta dentro de eval, se ejecutaría con los mismos permisos que su script php y podría ser utilizado para obtener información / acceso a su servidor. Puede ser bastante complicado asegurarse de que la entrada del usuario se limpie adecuadamente antes de entregarlo a eval. Hay otros problemas ... algunos de los cuales son discutibles


3
2018-06-04 16:24



PHP le aconseja que escriba su código de tal manera que se pueda ejecutar a través de call_user_func en lugar de hacer explícs explícitos.


3
2018-06-05 01:13