Reporte de Errores
Hablando de la seguridad en PHP, hay dos caras en lo que se concierne al
reporte de errores. Una es benéfica al incremento de la seguridad, la
otra va en dirección de su detrimento.
Una táctica de ataque típica involucra la acumulación de un perfil de
datos del sistema alimentándolo con datos inapropiados, y luego chequear
los tipos de errores que son devueltos, y sus contextos. Esto permite
que el cracker del sistema pueda adquirir información del servidor, para
así determinar posibles debilidades. Por ejemplo, si un atacante ha
recogido información sobre una página creada a partir de los datos de un
formulario, él podría intentar sobrescribir las variables, o
modificarlas:
Example #1 Ataque a Variables con una página HTML personalizada
<form method="post" action="destino_del_ataque?username=badfoo&password=badfoo">
<input type="hidden" name="username" value="badfoo" />
<input type="hidden" name="password" value="badfoo" />
</form>
Los errores de PHP que son devueltos normalmente pueden ser bastante
útiles para un desarrollador que esté tratando de depurar un script,
indicando cosas como la función o archivo que falló, el archivo PHP y el
número de línea en donde ocurren los fallos. Toda esta es información de
la que puede sacarse provecho. No es extraño que un desarrollador php
use show_source(),
highlight_string(), o
highlight_file() como medida de depuración, pero en
un sitio en producción, esta acción puede exponer variables ocultas,
sintaxis sin chequear, y otra información peligrosa. Algo especialmente
peligroso es ejecutar código que proviene de fuentes bien conocidas con
gestores de depuración incorporados, o que usan técnicas de depuración
comunes. Si el atacante puede determinar qué técnica general está
usando, puede intentar un ataque de fuerza bruta sobre una página,
enviando varias cadenas comunes de depuración:
Example #2 Explotación de variables comunes de depuración
<form method="post" action="destino_del_ataque?errors=Y&showerrors=1&debug=1">
<input type="hidden" name="errors" value="Y" />
<input type="hidden" name="showerrors" value="1" />
<input type="hidden" name="debug" value="1" />
</form>
Independientemente del método de gestión de errores, la capacidad de
conseguir que un sistema revele sus posibles estados de error representa
un camino para darle información al atacante.
Por ejemplo, el estilo mismo de un error de PHP genérico indica que el
sistema está ejecutando PHP. Si el atacante estuviera viendo una página
.html, y quisiera consultar qué está siendo usado para la generación de
ella por detrás (en busca de debilidades conocidas en el sistema),
podría determinar que el sistema fue creado usando PHP alimentándolo con
información equivocada.
Un error de función puede indicar si el sistema está ejecutando un tipo
particular de motor de base de datos, o dar pistas sobre cómo fue
programada o diseñada una página web. Esto facilita posteriores
investigaciones en determinados puertos abiertos de bases de datos, o en
busca de fallos específicos o debilidades en una página web. Al entregar
diferentes trozos de datos inválidos al sistema, por ejemplo, un
atacante puede determinar el orden de autenticación en un script, (a
partir de los números de línea de los errores) así como averiguar sobre
vulnerabilidades que pueden aprovecharse en diferentes puntos del
script.
Un error del sistema de archivos o en general de PHP puede indicar qué
permisos tiene el servidor web, así como la estructura y organización de
los archivos en el servidor web. Algún código de gestión de errores
escrito por el desarrollador puede agravar este problema, llevando a la
fácil explotación de información hasta entonces "escondida".
Existen tres soluciones principales a este problema. La primera es
revisar cuidadosamente todas las funciones, y tratar de compensar por la
mayoría de errores encontrados. La segunda es deshabilitar el reporte de
errores completamente del código que está siendo ejecutado. La tercera
es usar las funciones de gestión de errores personalizables de PHP para
crear su propio gestor de errores. Dependiendo de su política de
seguridad, puede encontrar que todas ellas pueden ser aplicables a su
situación.
Una forma de detectar este problema por adelantado es hacer uso del
reporte de errores propio de PHP (error_reporting()),
para ayudarle a asegurar su código y encontrar uso de variables que
pueda ser peligroso. Al probar su código, previamente a su entrega
final, con E_ALL, puede encontrar rápidamente áreas en donde sus
variables pueden estar abiertas a la manipulación y explotación en
distintas formas. Una vez esté listo para liberar su código, es buena
idea que deshabilite el reporte de errores por completo definiendo
error_reporting() a 0, o desactive la impresión de
errores usando la opción de php.ini display_errors,
de modo que pueda aislar su código de ataques potenciales. Si elige la
última opción, debe definir también la ruta a su archivo de registro
usando la directiva ini error_log, y habilitar
log_errors.
Example #3 Detección de variables peligrosas con E_ALL
<?php
if ($nombre_usuario) { // Variable no inicializada o chequeada antes de su uso
$login_correcto = 1;
}
if ($login_correcto == 1) { // Si la condición anterior falla, esta variable
// no se encuentra inicializada ni validada
// antes de su uso
readfile ("/informacion/altamente/confidencial/index.html");
}
?>