9.02.2008

Validación de datos de entrada con expresiones regulares en PHP

Ayer me llevé una buena sorpresa al leer un post que me llegó vía Buayacorp. Desde siempre he considerado fundamental la comprobación y validación de los parámetros de entrada de las aplicaciones web, algo imprescindible si se quiere garantizar en cierta medida el correcto funcionamiento de una aplicación o protegerla frente a diferentes tipos de ataques.

Para realizar estas validaciones he utilizado diversas técnicas, como comprobar si las variables están definidas o no, si son del tipo correcto, si los valores están entre los rangos permitidos, etc. Una de las herramientas más valiosas que hasta ayer consideraba más valiosas eran las expresiones regulares de PHP (POSIX).

Desde que comencé a utilizar estas funciones había un aviso en la documentación de PHP que me suscitaba cierta curiosidad. Este aviso decía y dice: Aviso Estas expresiones regulares no son seguras con material binario. Las Funciones PCRE lo son. Siempre me he preguntado a qué se refería la documentación con ese mensaje tan críptico, pero la verdad es que nunca pensé que pudiera afectar al uso que hacía de las expresiones regulares, no al menos en la parte de verificación de datos de formularios, información que llega en formato texto. Sin embargo, tal como dice Alex en su página, y tal como se ve también en una reciente contribución (01-04-2007, Edward Z. Yang) en la propia página de PHP, esto no es así.

La verdad es que no consigo entender cómo quien escribió ese aviso en la documentación, no fue más explícito teniendo en cuenta la importancia tiene. Esta claro que la responsabilidad de construir aplicaciones de forma segura recae en los desarrolladores, pero también es cierto que nosotros nos basamos en la documentación de las plataformas que utilizamos, por lo que si estas no están bien documentadas, o no explican la importancia de determinadas funcionalidades, mal vamos. Considero que esta contribución añadida por Edward podría haberse añadido hace varios años a la página de la documentación y todos habríamos entendido ese críptico aviso y sus implicaciones en la verificación de datos de entrada, por ejemplo.

Veamos cuál es el problema. En el siguiente código se muestra un fragmento de código PHP en el que se define una variable "key" y luego se realiza una expresión regular sobre ella, para comprobar si es un número de 1 a 6 dígitos. Si nos fijamos en el código podemos ver cómo en vez de definir la variable "key" como un número, le he concatenado un código binario nulo chr(0) (fin de cadena en C y C++) y a continuación una porción de código JavaScript. El resultado debería ser por tanto que la expresión regular dijera que no se cumple el patrón y se mostrara el mensaje de error, sin embargo el resultado no es este. Debido al caracter nulo que he añadido tras el número, y a que la función ereg no es segura con material binario, se cumple la expresión regular, por lo que se muestra su contenido.


alert('XSS')";
if(!ereg('^[0-9]{1,6}$', $key)){
echo "ERROR: El valor proporcionado no es un número de 1 a 6 dígitos";
}
else{
echo $key;
}

?>



Esto ya es una mala noticia debido a que la función no actúa como esperábamos, pero aún es peor, ya que aunque en el ejemplo he escrito el chr(0) directamente en código, parece ser que es trivial enviarlo como parte de un parámetro enviado por GET o POST, haciendo la aplicación absolutamente vulnerable a ataques XSS por ejemplo. Según se indica en diversos ejemplos que he encontrado, parece que para ello simplemente hay que codificar el caracter como en la petición, por ejemplo test.php?key=123456, aunque la verdad es que lo he probado con varios navegadores, Firefox, Explorer e incluso Lynx, y no he conseguido que falle… seguiré intentándolo.

Si preferimos no arriesgarnos, no debemos confiar únicamente en estas expresiones regulares para la validación de datos de entrada. En su lugar podemos utilizar las funciones de expresiones regulares basadas en PERL (PCRE), que antes había que activar manualmente en la compilación de PHP cuando esto era posible, y que al menos ahora, desde la versión PHP 4.2, vienen ya habilitadas por defecto.


Fuente: http://www.eslomas.com/index.php/archives/2007/04/17/validacion-de-datos-de-entrada-con-expresiones-regulares-en-php/

No hay comentarios: