in

Estate atento: funciones de PHP y WordPress que pueden hacer que tu sitio sea inseguro

Antes de implementar un nuevo complemento en WordPress, es una buena idea tener a tu lado una lista de funciones fáciles de usar incorrectamente. Echemos un vistazo más de cerca a algunas funciones que puedes y debes usar como parte de una estrategia de seguridad más amplia.

La seguridad de un sitio web de WordPress (o cualquier otro) es un problema multifacético. El paso más importante que cualquiera puede tomar para asegurarse de que un sitio sea seguro es tener en cuenta que ningún proceso o método es suficiente para garantizar que no ocurra nada malo. Pero hay cosas que puedes hacer para ayudarte. Uno de ellos es estar atento, en el código que escribes y el código de otros que implementas, en busca de funciones que puedan tener consecuencias negativas. En este artículo, cubriremos exactamente esas funciones que un desarrollador de WordPress debe pensar claramente antes de usar. El propio WordPress proporciona una biblioteca considerable de funciones, algunas de las cuales pueden ser peligrosas. Más allá de eso, hay muchas funciones PHP que un desarrollador de WordPress (PHP) usará con cierta frecuencia que puede ser peligrosa cuando se usa. Todas estas funciones tienen usos legítimos y seguros, pero también son funciones que pueden facilitar el abuso de su código para fines negativos. Cubriremos las cosas con más probabilidades de ser la causa de una vulnerabilidad de seguridad y por qué debes estar atento a ellas. Primero analizaremos las funciones PHP en su código que los malos actores pueden usar para el mal, y luego hablaremos sobre las funciones PHP específicas de WordPress que también pueden causar dolores de cabeza.

Funciones PHP a tener en cuenta  #

Como dijimos, PHP contiene muchas funciones fáciles de usar. Algunas de esas funciones son conocidas por la facilidad con la que las personas pueden hacer cosas malas con ellas. Todas estas funciones tienen un uso adecuado, pero ten cuidado con cómo las usas y cómo lo haces en un proyecto. Vamos a suponer que ya tienes citas mágicas y registros globales desactivados si tu versión de PHP los admite. Estaban desactivados de forma predeterminada en PHP 5 y posteriores, pero podrían activarse para versiones inferiores a 5.4. Pocos hosts lo permitieron, pero no creo que un artículo de seguridad de PHP esté realmente completo sin incluirlos. O una mención de que PHP 5.6 es la última versión 5.x que aún cuenta con soporte de seguridad continuo. Deberías estar en eso, al menos. Y ya deberías tener un plan para pasar a PHP 7. Después de eso, solo tendrás que lidiar con algunas funciones con riesgo. Empezando con…

extract Son malas noticias, especialmente en $_POST o similar  #

Afortunadamente, el uso de la función extract de PHP ha caído en desgracia. El núcleo de su uso era que podía ejecutarlo en una matriz de datos, y sus pares clave-valor se convertirían en variables vivas en su código. Entonces

$arr = array(
    'red' => 5
);
extract($arr);
echo $red; // 5

funcionaría. Esto es genial, pero también es realmente peligroso si estás extrayendo $_GET, $_POSTetc. En esos casos, esencialmente estás recreando el problema register_globals tú mismo: un atacante externo puede cambiar los valores de tus variables fácilmente agregando una cadena de consulta o un campo de formulario. La mejor solución es simple: no usar extract. Si creas la matriz que extraes, no es un problema de seguridad específico extract y, en algunos casos, puede ser útil. Pero todos los usos tienen el problema de confundir a los futuros lectores. Crear una matriz y llamar extract es más confuso que simplemente declarar sus variables. Así que te animo a hacer declaraciones manuales en su lugar, a menos que sea completamente inviable. Si debes usar extract en la entrada del usuario, siempre debes usar la bandera EXTR_SKIP. Esto todavía tiene el problema de la confusión, pero elimina la posibilidad de que un forastero malintencionado pueda cambiar tus valores preestablecidos a través de una simple cadena de consulta o una modificación del formulario web. (Porque «salta» los valores ya establecidos).

» eval Es malo» porque el código arbitrario da miedo  #

eval en PHP y en casi cualquier otro lenguaje que lo lleve siempre ocupa un lugar destacado en listas como ésta. Y por una buena razón. La documentación oficial de PHP en PHP.net lo dice francamente: PRECAUCIÓN. La construcción del lenguaje eval () es muy peligrosa porque permite la ejecución de código PHP arbitrario. Por tanto, se desaconseja su uso. Si has verificado cuidadosamente que no hay otra opción que usar esta construcción, presta especial atención a no pasar ningún dato proporcionado por el usuario sin validarlo adecuadamente de antemano. eval permite que cualquier cadena arbitraria en su programa se ejecute como si fuera código PHP. Eso significa que es útil para la “metaprogramación” en la que estás construyendo un programa que por sí mismo puede construir un programa. También es realmente peligroso porque si alguna vez permites que fuentes arbitrarias (como un cuadro de texto en una página web) se pasen inmediatamente a su evaluador eval de cadenas, de repente has hecho que sea trivialmente fácil para un atacante malintencionado hacer casi cualquier cosa que PHP pueda hacer en tu servidor. Esto incluye, obviamente, conectarse a la base de datos, eliminar archivos y casi cualquier otra cosa que alguien pueda hacer cuando estés conectado a una máquina mediante SSH. Esto es malo. Si debes usarlo en tu programa, debes hacer todo lo posible para asegurarte de no permitir que ingrese información arbitraria del usuario. Y si debe permitir que los usuarios arbitrarios accedan a las entradas eval, limita lo que pueden hacer a través de una lista negra de comandos que no les permita ejecutar, o (mejor, pero mucho más difícil de implementar) una lista blanca que son solo los comandos que considera a salvo. Mejor aún, solo permite una pequeña cantidad de cambios de parámetros específicos, como solo enteros validados. Pero siempre ten en cuenta esta línea de Rasmus Lerdorf, el fundador de PHP:

«Si` eval () `es la respuesta, es casi seguro que estás haciendo la pregunta incorrecta».

Variaciones en eval #

Hay, además de las conocidas eval, una variedad de otras formas en las que PHP históricamente ha soportado cadenas-evaluadas como código. Los dos que son más relevantes para los desarrolladores de WordPress son preg_replace /emodificador y create_function. Cada uno funciona de forma un poco diferente, y preg_replace después de PHP 5.5.0 no funciona en absoluto. (PHP 5.5 y versiones anteriores ya no reciben actualizaciones de seguridad oficiales y, por lo tanto, es mejor que no se utilicen).

Los modificadores /e en Regex también son «malvados»  #

Si estás ejecutando PHP 5.4.x o inferior, querrás estar atento a las llamadas preg_replace de PHP que terminan con una e. Eso puede verse así:

$html = preg_replace(
    '((.*?))e',
    '"" . strtoupper("$2") . ""',
    $html
);)
// or
$html = preg_replace(
    '~(.*?)~e',
    '"" . strtoupper("$2") . ""',
    $html
);)

PHP ofrece varias formas de «cercar» en su expresión regular, pero lo principal que deseas buscar es «e» como último carácter del primer argumento de preg_replace. Si estás allí, en realidad estás pasando todo el segmento encontrado como argumento a su PHP en línea y luego eval lo estás ingiriendo. Esto tiene exactamente los mismos problemas que eval si permitiera que la entrada del usuario entre en su función. El código de ejemplo se puede reemplazar usando en su lugar preg_replace_callback. La ventaja de esto es que has escrito tu función, por lo que es más difícil para un atacante cambiar lo que se evalúa. Entonces escribirías lo anterior como:

// uppercase headings
$html = preg_replace_callback(
    '((.*?))',
    function ($m) {
        return "" . strtoupper($m[2]) . "";
    },
    $html
);

Permitir que el usuario ingrese create_function también es malo…  #

PHP también tiene la función create_function. Esto ahora está obsoleto en PHP 7.2, pero era muy similar a eval y tenía los mismos inconvenientes básicos: permite que una cadena (el segundo argumento) se convierta en PHP ejecutable. Y tenía los mismos riesgos: es demasiado fácil darle accidentalmente a un cracker inteligente la capacidad de hacer cualquier cosa en tu servidor si no tienes cuidado. Éste, si está en PHP por encima de 5.3, es incluso más fácil de arreglar que preg_replace sin embargo. Puedes crear tu propia función anónima sin utilizar cadenas como intermediarios. Esto es más seguro y más legible, al menos a mis ojos.

assert También es eval– Like  #

assert no es una función que veo que usan muchos desarrolladores de PHP, en WordPress o fuera de él. Su intención es hacer afirmaciones muy ligeras sobre las condiciones previas para tu código. Pero también admite una operación de tipo eval. Por esa razón, debes ser tan cauteloso como lo es eval. Las afirmaciones basadas en cadenas (el corazón de por qué esto es malo) también están obsoletas en PHP 7.2, lo que significa que deberían ser menos preocupantes en el futuro.

La inclusión de archivos variables es una forma de permitir posiblemente la ejecución de PHP incontrolada  #

Hemos explorado bastante bien por qué eval es malo, pero algo como includeo require($filename'.php') puede, especialmente cuando $filename se establece a partir de un valor controlable por el usuario, ser igualmente malas noticias. La razón es sutilmente diferente a eval. Los nombres de archivo variables se usan a menudo para cosas como el enrutamiento simple de URL a archivo en aplicaciones PHP que no son de WordPress. Pero es posible que también los veas utilizados en WordPress. El meollo del problema es que cuando include o require (o include_once o require_once) está haciendo que tu script ejecute el archivo incluido. Es, más o menos, conceptualizar ese archivo eval, aunque rara vez lo pensamos de esa manera. Si has escrito todos los archivos que tu variable include podría extraer y has considerado lo que sucedería cuando lo hicieras, está bien. Pero es una mala noticia si no lo has considerado include ING password.php o wp-config.php va a hacer. También es una mala noticia que alguien pueda agregar un archivo malicioso y luego ejecutarlo include (aunque en ese momento probablemente tengas problemas mayores). Sin embargo, la solución a esto no es demasiado difícil: el código rígido se incluye cuando puede. Cuando no puedas, ten una lista blanca (mejor) o una lista negra de archivos que se pueden incluir. Si los archivos en la lista blanca (es decir, has auditado lo que hace cuando se agrega), sabrás que está a salvo. Si no está en tu lista blanca, tu script no lo incluirá. Con ese simple ajuste, estás bastante seguro. Una lista blanca se vería así:

$white_list = [‘db.php’, filter.php’, ‘condense.php’] If (in_array($white_list, $file_to_include)) { include($file_to_include); }

Nunca uses como pass user shell_exec y variantes  #

Éste es un grande. shell_exec, system, exec, Y acentos abiertos en toda PHP permiten que el código que se está ejecutando sea vulnerable. Esto es similar a lo que hace peligros a eval pero duplicado. Duplicado porque si dejas que el usuario ingrese aquí descuidadamente, el atacante ni siquiera está sujeto a las restricciones de PHP. La capacidad de ejecutar comandos de shell desde PHP puede resultar muy útil como desarrollador. Pero si alguna vez dejas entrar a un usuario, éeste tiene la capacidad de ganar subrepticiamente muchos poderes peligrosos. Así que iría tan lejos como para decir que la entrada del usuario nunca debe pasarse a funciones de tipo shell_exec. La mejor manera que se me ocurre para manejar este tipo de situación, si tuviera la tentación de implementarlo, sería proporcionar a los usuarios acceso a un pequeño conjunto de comandos de shell predefinidos y seguros conocidos. Eso podría ser posible de asegurar. Pero incluso entonces te advierto que tengas mucho cuidado.

Estate atento con unserialize; Ejecuta código automáticamente  #

La acción principal de llamar serialize a un objeto PHP vivo, almacenar esos datos en algún lugar y luego usar ese valor almacenado más tarde para unserialize y que ese objeto vuelva a la vida es genial. También es bastante común, pero puede ser peligroso. ¿Por qué arriesgado? Si la entrada a esa llamada unserialize no es completamente segura (digamos que se almacena como una cookie en lugar de en su base de datos…), un atacante puede cambiar el estado interno de tu objeto de una manera que haga que la llamada unserialize haga algo malo. Este exploit es más esotérico y es menos probable que se note que un problema eval. Pero si estás utilizando una cookie como mecanismo de almacenamiento de datos serializados, no la utilices serialize para esos datos. Utiliza algo como json_encode y json_decode. Con esos dos PHP nunca ejecutarás automáticamente ningún código. La vulnerabilidad principal aquí es que cuando PHP ingresa una cadena unserialize en una clase, llama al método mágico __wakeup en esa clase. Si te permites una entrada de usuario no validada unserialized, algo como una llamada a la base de datos o la eliminación de un archivo en el método __wakeup podría apuntar a una ubicación peligrosa o indeseable. unserialize se diferencia de las vulnerabilidades eval porque requiere el uso de métodos mágicos en los objetos. En lugar de crear tu propio código, el atacante se ve obligado a abusar de sus métodos ya escritos en un objeto. Tanto las métodos __destruct y __toString en los objetos también son peligrosos, como esta página Wiki OWASP explica. En general, está bien si no utilizas los métodos __wakeup, __destruct o __toString en tus clases. Pero debido a que es posible que más adelante veas a alguien que añade a una clase, es una buena idea de no dejar que un usuario use sus llamadas a serialize y unserialize y pasar todos los datos públicos para ese tipo de uso, aunque algo así como JSON (json_encode y json_decode) donde hay código nunca es automática la ejecución.

Obtener URL con file_get_contents es arriesgado  #

Una práctica común cuando se escribe rápidamente un código PHP que tiene que llamar a una URL externa es buscar file_get_contents. Es rápido, es fácil, pero no es muy seguro. El problema file_get_contents es sutil, pero es bastante común que los hosts a veces configuren PHP para ni siquiera permitirte acceder a URL externas. Esto está destinado a protegerte. El problema aquí es que file_get_contents buscará páginas remotas por ti. Pero cuando lo hace, no verifica la integridad de la conexión del protocolo HTTPS. Lo que eso significa que tu script podría ser potencialmente víctima de un ataque man-in-the-middle que permitiría a un atacante poner prácticamente lo que quiera en el resultado de su página file_get_contents. Éste es un ataque más esotérico. Pero para protegerme cuando escribo PHP moderno (basado en Composer), casi siempre uso Guzzle para envolver la API cURL más segura. En WordPress, es aún más fácil: usar wp_remote_get. Funciona de forma mucho más consistente que file_get_contents, y de forma predeterminada, la verificación de las conexiones SSL. (Puedes desactivar eso, pero, um, tal vez no…) Mejor aún, pero un poco más molesto para hablar, son wp_safe_remote_get, etc. Estos funcionan de manera idéntica a las funciones sin su nombre safe_, pero se asegurarán de que Los redireccionamientos y reenvíos inseguros no ocurren en el camino.

No confíes ciegamente en la validación de URL de filter_var #

Esto es un poco oscuro, así que felicitaciones a Chris Weigman por explicarlo en esta charla de WordCamp. En general, PHP filter_var es una excelente manera de validar o desinfectar datos. (Aunque, no te confundas sobre lo que estás tratando de hacer…) El problema aquí es bastante específico: si estás tratando de usarlo para asegurarte de que una URL sea segura, filter_var no valida el protocolo. Eso no suele ser un problema, pero si estás pasando la entrada del usuario a este método para la validación y lo estás utilizando FILTER_VALIDATE_URL, algo como javascript://comment%0aalert(1) pasará. Es decir, este puede ser un vector muy bueno para un ataque XSS básico en un lugar que no esperabas. Para validar una URL, la función esc_url de WordPress tendrá un impacto similar, pero solo deja pasar los protocolos permitidos. javascript no está en la lista predeterminada, por lo que lo mantendría a salvo. Sin embargo, a diferencia de filter_var esto devolverá una cadena vacía (no falsa) para un protocolo no permitido que se te pase.

Funciones específicas de WordPress para vigilar  #

Además de las funciones potencialmente vulnerables del núcleo de PHP, hay algunas funciones específicas de WordPress que pueden ser un poco complicadas. Algunas de estas son muy similares a la variedad de funciones peligrosas enumeradas anteriormente, algunas un poco diferentes.

WordPress no serializa con maybe_unserialize #

Esto probablemente sea obvio si lees lo anterior. En WordPress hay una función llamada maybe_unserialize y, como puedes imaginar, anula la serialización de lo que se te pasa si es necesario. No hay ninguna vulnerabilidad nueva que esto introduzca, el problema es simplemente que, al igual que la función principal unserialize, ésta puede hacer que un objeto vulnerable sea explotado cuando no está serializado.

is_admin ¡No responde si un usuario es administrador! #

Éste es bastante simple, pero la función tiene un nombre ambiguo, por lo que es propenso a confundir a la gente o ser extrañado si tiene prisa. Siempre debes verificar que un usuario que esté tratando de realizar una acción en WordPress tenga los derechos y privilegios necesarios para realizar esa acción. Para eso, debes usar la función current_user_can. Pero podrías, erróneamente, pensar que is_admin te dirá si el usuario actual es una cuenta de nivel de administrador y, por lo tanto, deberías poder configurar una opción que usa tu complemento. Esto es un error. Lo que is_admin hace en WordPress es, en cambio, decirle si la carga de la página actual está en el lado de administración del sitio (frente a la parte frontal). Por lo tanto, todos los usuarios que puedan acceder a una página de administración (como el «Panel de control») podrán pasar potencialmente esta verificación. Siempre que recuerdes que is_admin se trata del tipo de página, no del usuario actual, estará bien.

Hay más por hacer, pero este es un gran comienzo  #

La seguridad es mucho más que simplemente estar atento a las funciones en tu código que los atacantes pueden hacer un mal uso. Por ejemplo, no discutimos en profundidad la necesidad de validar y desinfectar todos los datos que recibes de los usuarios y escapar de ellos antes de ponerlos en una página web. Pero puedes y debes usar esto como parte de una estrategia de seguridad más amplia. Mantener esta lista de funciones fáciles de usar incorrectamente a tu lado mientras realizas una inspección final antes de implementar un nuevo complemento en WordPress es una gran idea. Pero también querrás asegurarte de confiar en la seguridad de tu alojamiento, asegurarte de que tus usuarios tengan buenas contraseñas y mucho más. Lo fundamental para recordar acerca de la seguridad es que tu eslabón más débil es el que importa. Las buenas prácticas en un área refuerzan los posibles puntos débiles en otro, pero nunca pueden corregirlo por completo. Pero estate atento a estas funciones, y tendrás una ventaja en la mayoría.

¿Qué opinas?

Escrito por Wombat

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

10 complementos de creador de páginas de arrastrar y soltar: crea cualquier sitio web sin esfuerzo

Revisión honesta de WP Rocket: datos de prueba reales + la mejor configuración en 2022