martes, 3 de marzo de 2009

12 trucos de seguridad web

Ayer mismo fue publicado por el SANS Institute un documento que nos ofrece 12 trucos para mejorar la seguridad de nuestras aplicaciones web. El autor, el conocido Ed Skoudis, Instructor de SANS y responsable del temario de los cursos de Incident Handling, Técnicas de Hacking y Test de Intrusión/Hacking Ético.

Los 12 trucos son los siguientes, con mi propia interpretación y comentarios:
  1. Usa librerías de validación de datos de entrada: En lugar de programarte unas ad-hoc, utiliza librerías conocidas, sus desarrolladores han invertido muchas más horas que tú y han sido mucho más testeadas. El proyecto OWASP es un buen sitio donde conseguir buenas librerías de este tipo.
  2. Especifica los tipos de las variables: Es una buena manera de evitar problemas en la validación de datos de entrada de aquellos campos de los que se esperen valores muy concretos, por ejemplo valores enteros. Los campos en los que se introducen enteros son un gran punto de entrada para los ataques web, ya que ni tan siquiera son necesarias comillas. No obstante, si dichos campos fueran verificados comprobando si el valor obtenido es un entero o no, resultaría imposible para un atacante poder inyectar nada que no fuera un entero. Por lo tanto, si el resultado tiene que ser un entero, comprueba que sea un entero, y si tiene que ser un NIF, comprueba que son los números requeridos seguido de una letra del alfabeto estandar e ignora otro tipo de caracteres, esto nos ahorrará muchos disgustos.
  3. No definas los caracteres incorrectos en lugar de definir los correctos: No podemos garantizar que conocemos todos los ataques existentes, y por lo tanto no podemos garantizar que no permitir determinados caracteres va a detener todos los tipos de ataque. Sin embargo, sí que podemos saber que juego de caracteres va a usar la aplicación y prohibir todos los demás, de esta manera evitamos sufrir ataques tanto conocidos como hasta ahora desconocidos por nosotros.
  4. Limita el tamaño de la entrada: En un campo "edad", con 3 dígios es suficiente (nadie va a tener más de 999 años), por lo tanto manejar valores de entrada más largos para ese campo sólo puede propiciar un espacio en el que un intruso puede intentar realizar algún tipo de ataque o inyección. Una implementación posible es, por ejemplo, la clase "Validator" de Java.
  5. Canonizar antes del filtrado: Se llama "canonizar" a convertir los caracteres encodeados en cualquier juego de caracteres a un juego de caracteres dado. Utilizar diferentes encodings es una práctica habitual para evitar los filtrados de las aplicaciones web por parte de los atacantes. Utilizar funciones como la ESAPI.encoder().canonicalize() permite evitar este tipo de ataques, puesto que tras convertir cualquier entrada a un juego de caracteres conocido ya podemos filtrar sin temor a este tipo de técnicas.
  6. Filtra todas las entradas: Cualquier dato de entrada a la aplicación web puede ser alterado y por tanto debe ser verificado. Muchas veces los desarrolladores tienden a pensar que hay campos que no pueden ser modificados, como las cookies, los valores de un desplegable o los campos hidden. Sin embargo, todos ellos pueden ser igualmente alterados por medio de proxys y otras técnicas de hacking, y por tanto deben ser verificados.
  7. Filtrar en el lado servidor: No podemos tener ningún tipo de control sobre lo que se ejecuta en el lado del cliente, por lo que no se debe delegar en esta parte ningún tipo de filtrado. El uso de proxies y otras técnicas permitirían modificaciones de los datos tras ser enviadas por el navegador, por lo que el atacante podría modificar los parámetros sin ningún tipo de restricción, haciendo inútil la validación realizada en el lado cliente. Por ello, la validación debe ser realizada siempre en el lado servidor.
  8. No pasa nada por utilizar varias capas de validación: Esta práctica fortalece aún más la seguridad del sistema, siguiendo un diseño de defensa en profundidad.
  9. Utiliza encoding de salida: Algunos ataques como los de Cross Site Scripting (XSS) consisten en introducir código de script que es ejecutado en los clientes al ser devuelto por la aplicación. Una manera de evitarlo es encodear también la salida de los datos, de tal manera que caracteres peligrosos como el "menor que" son traducidos a sus correspondientes caracteres en HTML, con lo que ya no serán interpretados por el navegador.
  10. Elije el encoding adecuado para la salida: Dependiendo de como vaya a ser interpretado, utiliza HTML, XML, comandos del sistema operativo, etc.
  11. Realiza revisiones de código: Si puedes permitirtelo, es muy positivo que personal especializado en seguridad externo al proyecto de desarrollo realice un análisis del código para detectar vulnerabilidades.
  12. Realiza un test de intrusión: Otro medio para verificar el estado final de tu aplicación web.

  13. Y a esta lista de Ed Skoudis, yo le añado las recomendaciones número 13, 14 y 15 de mi propia cosecha:

  14. Mantén el código lo más sencillo y bien documentado/comentado que puedas: La vida de un software está llena de actualizaciones, de persoans diferentes metiendole mano y de "esto tiene que estar para ayer", pero añadir correcciones descontroladamente puede ofuscar el código y hacerlo cada vez menos mantenible, y por lo tanto será más fácil que nos dejemos ese parámetro nuevo que añadimos con prisas y del que no realizamos validación, y al final es por ahí por donde todo se complica. Intentar siempre que todo el equipo conozca como deben codificarse las entradas de datos según las anteriores reglas, y si es posible que alguien lo verifique (como dicen las reglas 11 y 12).
  15. Implementa detección de intrusiones: Existen librerías de detección de intrusiones como PHP-IDS que pueden ser utilizadas para detectar intentos de intrusión. No sólo basta con que los intrusos no consigan sus objetivos, si conseguimos detectarlos y filtrarlos antes de que jueguen demasiado rato con nuestra aplicación como para encontrar algo, mucho mejor.
  16. Implementa un buen registro de log: En muchas ocasiones los que nos enfrentamos a la gestión de incidentes nos encontramos con que vamos a ver "que ha pasado" y los sistemas no guardan ningún tipo de registro, lo que ha pasado ya pasó, pero la información guardada en el registro es muy escasa, tan escasa que es imposible saber que pasó. Recordad que los logs típicos de aplicaciones web no guardan demasiada información, practicamente sólo registran la URL visitada, y se dejan información tan importante como la información o ficheros subidos por medio del método POST, las cabeceras de la llamada HTTP, la cookie empleada, etc. Por ello es importante que registremos en un log cualquier anomalía que detectemos, por ejemplo el uso de identificadores de sesión inválidos, porque si tenemos un incidente, cuando el Incident Handler revise los logs, verá que alguien ha estado intentando buscar identificadores de sesión válidos para realizar un robo de sesión (por ejemplo). De lo contrario, probablemente poco os podrá decir, y por lo tanto poco podreis aprender de vuestro incidente, factor fundamental para que no vuelva a suceder.

Como dice el autor, seguir estas medidas de seguridad no asegura que nuestras aplicaciones web sean "a prueba de balas", pero desde luego vamos a obligar a los intrusos a emplear una buena cantidad de horas si quieren sacar algo de provecho de nuestros sistemas, probablemente tantas horas que no merecerá la pena en ninguno de los casos, que es al final lo que persigue la seguridad, ofrecer tantas dificultades a los intrusos que el premio obtenido por romper la seguridad no sea compensado por la recompensa que se obtiene.

Librerías:
Yo soy un total fan del proyecto OWASP, pero si alguien tiene sus librerías favoritas que deje en enlace como comentario y las voy añadiendo a la lista.

No hay comentarios :