¿Cuándo es eval evil en php?


En todos los años que he estado desarrollando en php, siempre he escuchado que usar eval() es malo.

Considerando el siguiente código, ¿no tendría sentido usar 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).';');
 77
Author: Nathaniel Ford, 2009-06-04

18 answers

Yo sería cauteloso al llamar a eval () maldad pura. La evaluación dinámica es una herramienta poderosa y a veces puede ser un salvavidas. Con eval () se puede trabajar alrededor de las deficiencias de PHP (ver más abajo).

Los principales problemas con eval () son:

  • Entrada potencialmente insegura. Pasar un parámetro no confiable es una forma de fallar. A menudo no es una tarea trivial asegurarse de que un parámetro (o parte de él) es totalmente confiable.
  • Problema. Usando eval () hace código inteligente, por lo tanto más difícil de seguir. Para citar a Brian Kernighan " Depurar es dos veces más 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 principal problema 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 debería intentar otra cosa.
  3. Si no está seguro, vaya a 2.
  4. De lo contrario, sea muy, muy cuidadoso.
 121
Author: Michał Rudnicki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-25 15:08:11

Eval es malo cuando solo hay la más mínima posibilidad de que userinput esté incluido en la cadena evaluada. Cuando haces una evaluación sin contenido proveniente de un usuario, deberías estar seguro.

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

Así que como regla general: Olvídalo. Cuando eval es la respuesta estás probablemente haciendo la pregunta equivocada! ;-)

 37
Author: Patrick Cornelissen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-24 07:28:17

Eval() es igualmente malo en todo momento.

"¿Cuándo eval() no es malo?"es la pregunta equivocada que hacer en mi opinión, porque parece implicar que los inconvenientes de usar 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 de eso) 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 sea optimizado por una 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 que sea absolutamente necesario usar eval() - PHP es un lenguaje de programación completamente funcional sin él.

Si realmente ves estos como males o si puedes justificar personalmente el uso de eval() en algunos casos depende de ti. A algunos, los males son demasiado grandes para justificarlo, y para otros, eval() es un atajo útil.

Sin embargo, si ves eval() como malo, es malo en todo momento. No pierde mágicamente su maldad dependiendo del contexto.

 17
Author: thomasrutter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-16 23:58:19

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

No es realmente más elegante sin embargo. Esto es básicamente un problema de análisis de texto, y abusar del analizador de PHP para manejar parece un poco hackeado. Si desea abusar de las características del lenguaje, ¿por qué no abusar del analizador JSON? Al menos con el analizador JSON, no hay ninguna 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 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
Author: BlackAura,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-04 16:21:19

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

En el ejemplo anterior, esto no es un problema.

 11
Author: GreenieMeanie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-04 15:46:50

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

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

Un ejemplo sencillo:

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

Un ejemplo dañino:

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

Le aconsejaría que no use eval() pero si lo hace, asegúrese de validar / incluir en la lista blanca todas las entradas.

 8
Author: Alix Axel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-14 02:36:04

Voy a robar descaradamente el contenido aquí:

  1. La evaluación por su naturaleza siempre va a ser una preocupación 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 es 10 veces más lento que el código normal y 28 veces más lento en PHP 5.1 beta1.

Blog.joshuaeichorn.com: usando-eval-in-php

 7
Author: stefs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-04 16:51:01

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

También siento que, dado que el 95% (o más) de los usos de eval son activamente peligrosos, el pequeño ahorro de tiempo potencial que podría proporcionar en otros casos no vale la pena caer en la mala práctica de usarlo. Además, más tarde tendrás que explicar a tus secuaces por qué tu uso de eval es bueno y el de ellos malo.

Y, por supuesto, tu PHP termina pareciéndose a 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) Tentará a la gente a usarlo inapropiadamente como un atajo en otro lugar

En el primer caso, se corre el riesgo (obviamente, no cuando se está evaluando una cadena conocida) de ejecución arbitraria de código. Sus entradas pueden no ser tan conocido o tan fijo como crees, sin embargo.

Es más probable (en este caso) que simplemente se bloquee, y su cadena terminará con un mensaje de error gratuito oscuro. En mi humilde opinión, todo el código debe fallar tan prolijamente como sea posible, en su defecto debería lanzar una excepción (como la forma de error más manejable).

Sugeriría que, en este ejemplo, estás codificando por coincidencia en lugar de codificar por comportamiento. Sí, la sentencia SQL enum (¿y está seguro de la enumeración de ese campo? - ¿llamaste a la campo derecho de la tabla derecha de la versión derecha de la base de datos? ¿Realmente respondió?) sucede que se parece a la sintaxis de declaración de matriz en PHP, pero sugeriría que lo que realmente desea hacer no es encontrar el camino más corto de entrada a salida, sino abordar la tarea especificada:

  • Identifica que tienes una enumeración
  • Extraer la lista interna
  • Descomprimir los valores de la lista

Que es aproximadamente lo que su opción uno hace, pero me gustaría envolver algunos si y comentarios alrededor de él para mayor claridad y seguridad (por ejemplo, si el primer partido no coincide, lanzar excepción o establecer resultado nulo).

Todavía hay algunos posibles problemas con comas o comillas escapadas, y probablemente debería descomprimir los datos y luego des-comillas, pero al menos trata los datos como datos, en lugar de como código.

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

 5
Author: Parsingphase,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-04 16:19:59

También pagaría algo de consideración a las personas que mantienen su código.

Eval() no es la facilidad para mirar y saber lo que se supone que debe suceder, su ejemplo no es tan malo, pero en otros lugares puede ser una pesadilla correcta.

 4
Author: Phil Carter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-04 16:00:30

Eval evalúa una cadena como código, el problema con eso es que si la cadena está de alguna manera "contaminada" podría exponer enormes 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 introducir 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 sea correcta limpiado antes de entregarlo a eval. Hay otros problemas... algunos de los cuales son discutibles

 3
Author: Toby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-04 16:24:00

PHP le aconseja que escriba su código de tal manera que pueda ejecutarse a través de call_user_func en lugar de hacer evaluaciones explícitas.

 3
Author: Nolte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-05 01:13:44

eval() es siempre mal.

  • por razones de seguridad
  • por razones de rendimiento
  • por razones de legibilidad / reutilización
  • por razones IDE / herramienta
  • por razones de depuración
  • siempre hay una mejor manera
 3
Author: Francois Bourgeois,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-31 13:50:07

Otra razón por la que eval es mala es que no se podía almacenar en caché por cachés de bytecode PHP como eAccelertor o ACP.

 2
Author: TheHippo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-14 04:00:45

Es la mala programación la que hace que eval() sea mala, no la función. Lo uso a veces, ya que no puedo evitarlo en la programación dinámica en múltiples sitios. No puedo tener PHP siendo analizado en un sitio, ya que no voy a recibir las cosas que quiero. ¡Solo recibiría un resultado! Estoy feliz de que exista una función como eval (), ya que hace mi vida mucho más fácil. ¿Entrada del usuario? Solo los malos programadores se enganchan con hackers. No me preocupo por eso.

 2
Author: Igor M. - PortalPress.org,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-27 12:29:27

Es la mala programación la que hace que eval() sea mala, no la función. Lo uso a veces, ya que no puedo evitarlo en la programación dinámica en múltiples sitios. No puedo tener PHP siendo analizado en un sitio, ya que no voy a recibir las cosas que quiero. ¡Solo recibiría un resultado! Estoy feliz de que exista una función como eval (), ya que hace mi vida mucho más fácil. ¿Entrada del usuario? Solo los malos programadores se enganchan con hackers. No me preocupo por eso.

Predigo que tendrá graves problemas pronto...

Con toda honestidad, no hay absolutamente ningún buen uso para una función exorbitante como eval, en un lenguaje interpretado como PHP. Nunca he visto a eval realizar funciones de programa que no podrían haberse ejecutado usando otras formas más seguras...

Eval es la raíz de todo mal, estoy totalmente de acuerdo, para todas las personas que piensan que probar la entrada del usuario ayudará. Piénselo dos veces, la entrada del usuario puede venir en muchas formas diferentes, y mientras hablamos los hackers están explotando eso función que no te importaba lo suficiente. En mi opinión, simplemente evite la evaluación por completo.

He visto ejemplos elaborados para abusar de la función de evaluación que superó mi propia creatividad. Desde una postura de seguridad, evite a toda costa, e incluso iría tan lejos como para exigir que sea al menos una opción en la configuración de PHP, en lugar de un 'dado'.

 2
Author: Braincracking,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-26 15:00:02

Solía usar eval() mucho, pero encontré que la mayoría de los casos no tienes que usar eval para hacer trucos. Bueno, tienes call_user_func () y call_user_func_array () en PHP. Es lo suficientemente bueno para llamar estática y dinámicamente a cualquier método.

Para realizar una llamada estática construye tu callback como array('class_name', 'method_name'), o incluso como cadena simple como 'class_name::method_name'. Para realizar una llamada dinámica use la devolución de llamada estilo array (object object, 'method').

El único uso sensato for eval () es escribir un compilador personalizado. Hice uno, pero eval sigue siendo malo, porque es muy difícil de depurar. Lo peor es el error fatal en el código evaled bloquea el código que lo llamó. He utilizado la extensión Parsekit PECL para comprobar la sintaxis al menos, pero todavía no hay alegría - tratar de hacer referencia a la clase desconocida y toda la aplicación se bloquea.

 1
Author: Harry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-14 01:56:17

Aparte de las preocupaciones de seguridad, eval() no puede ser compilada, optimizada o almacenada en caché de opcode, por lo que siempre será más lenta { mucho más lenta than que el código php normal. Por lo tanto, es inoperante usar eval, aunque eso no lo hace malo. (goto es malo, eval es solo mala práctica / código maloliente / feo)

 0
Author: Aron Cederholm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-29 01:59:13

Aquí hay una solución para ejecutar código PHP extraído de una base de datos sin usar eval. Permite todas las funciones y excepciones del ámbito:

$rowId=1;  //database row id
$code="echo 'hello'; echo '\nThis is a test\n'; echo date(\"Y-m-d\");"; //php code pulled from database

$func="func{$rowId}";

file_put_contents('/tmp/tempFunction.php',"<?php\nfunction $func() {\n global \$rowId;\n$code\n}\n".chr(63).">");

include '/tmp/tempFunction.php';
call_user_func($func);
unlink ('/tmp/tempFunction.php');

Básicamente crea una función única con el código incluido en un archivo de texto, incluye el archivo, llama a la función, luego elimina el archivo cuando termina con él. Estoy usando esto para realizar ingestions/syncronizations diario de la base de datos donde cada paso requiere el código único manejar para procesar. Esto ha resuelto todos los problemas a los que me enfrentaba.

 0
Author: Jason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-02 18:12:53