Filtrado de parámetros de entrada. Recomendaciones

Parámetros de entrada. Ese gran agujero de seguridad por el que se cuelan dos de las vulnerabilidades más comunes en cualquier aplicación web: Inyección SQL y Cross-Site Scripting. No están por casualidad en los puestos número uno y tres del TOP 10 de OWASP de este año 2013.

Y es que es una batalla por la que los pentesters luchamos a diario. La formación sobre desarrollo seguro sigue siendo, a día de hoy, escasa. Por poner un ejemplo, de todo el material de un máster sobre desarrollo web al que he podido echar un vistazo, de un año de duración, las referencias sobre seguridad son una única sección, de un tema, de una asignatura, con un total de 9 páginas. La información sobre la correcta implementación de medidas de seguridad es obviamente insuficiente.

Pero el problema también se encuentra en nuestro lado de la mesa. Si después de haber entregado un informe de un test de intrusión a un cliente, las correcciones tomadas han sido insuficientes, es que no hemos sido capaces de transmitir la gravedad de la vulnerabilidad, ni la forma correcta de mitigarlas. La solución “filtrar correctamente los parámetros de entrada” necesita una explicación más extensa sobre lo que quiere decir “filtrar correctamente”.

Por este motivo, me he decidido a enumerar unas recomendaciones generales, pero un poco más precisas, sobre el filtrado de parámetros de entrada. Empecemos:

  • En primer lugar, una pregunta recurrente: ¿Dónde deben validarse los datos de entrada? ¿En el lado del cliente? ¿O en el del servidor? Seguramente os habréis dado cuenta de que es una pregunta trampa porque la respuesta correcta es en los dos lados ;) . Es imprescindible que toda validación y filtrado de datos de entrada se realice en el lado del servidor, ya que el lado del cliente es ejecutado por el usuario, y las restricciones se pueden evadir. Pero también es recomendable añadir validación en el lado del cliente, no por temas de seguridad, pero si por usabilidad. A pesar de que el servidor va a comprobar que todo lo que reciba es correcto, viene bien que un javascript compruebe también que se están escribiendo datos correctos, por ejemplo en un formulario. Ahorras tiempo al usuario, y ahorras ancho de banda al servidor.
  • Filtrar TODA la entrada. No se debe limitar a los datos que escribe el usuario en la barra del navegador, o los campos de un formulario. También los campos ocultos HTML de un formulario, las cookies, cabeceras HTTP. No presuponer que el usuario no va a tocar esos datos porque la aplicación no dispone de esa funcionalidad. Con un proxy HTTP, o con una simple extensión del navegador, como tamper data, es posible modificar cualquier cosa que se vaya a enviar de nuestro navegador al servidor.
  • No reinventar la rueda: no complicarse la vida. No es recomendable crear desde cero una implementación propia, ya que probablemente no contemple todos los casos posibles. Mejor usar funciones ya testeadas y maduras como las disponibles en prácticamente cualquier lenguaje de programación o framework. También se puede usar la librería ESAPI de OWASP, con APIs para Java, Python, .NET, PHP, ASP, entre otros.
  • Comprueba tipos de variables: si un parámetro de entrada solo espera recibir un entero, comprueba si lo que recibe es efectivamente un entero. En datos como IDs de objetos suele ser bastante útil, del estilo de http://a/index.php?id=400
  • Como complemento al punto anterior, usa listas blancas de datos permitidos, y deniega todo lo demás. Es mucho más sencillo definir lo permitido, que enumerar todo lo prohibido. Por ejemplo, para una cadena de texto, se puede definir que sea válida toda cadena que contenga a..z, A..Z, 0..9 y todo lo demás eliminarlo. Con esto se evita el uso de caracteres especiales.
  • Si no se desea filtrar caracteres especiales, por requerimientos de la aplicación, usa codificación de salida a la hora de representar los datos. Por ejemplo, codificación HTML para caracteres especiales, como “>” que pasa a ser “>” o “&” “&amp”.
  • Antes de filtrar, codifica. Los datos de entrada pueden venir de muchas formas codificadas. Siguiendo el ejemplo del anterior punto, el carácter “>” se puede representar también como “&gt”, “%3E”, o “&#x3E”. Es conveniente normalizar todo el texto, antes de aplicar los filtros. La librería ESAPI dispone de la función canonicalize() para pasar una cadena directamente a ASCII.
  • Controla el tamaño de la entrada: no sólo es recomendable controlar que entra, si no también cuanto. Con esto, se evita cualquier problema de denegación de servicio, por saturar al servidor con una entrada enorme, y también de los peligrosos de desbordamientos de buffer.

Como veis, son bastantes las consideraciones que hay que tener en cuenta para que nuestra aplicación sea robusta de cara a los datos que entren. No obstante, una vez comprendida la posible vulnerabilidad y su riesgo, es fácil aplicarle la medida correcta.

Comments

  1. Muy buen artículo, es algo que todo desarrollador web debería estudiar y tener en cuenta…
    SAludos…

Trackbacks

  1. […] Parámetros de entrada. Ese gran agujero de seguridad por el que se cuelan dos de las vulnerabilidades más comunes en cualquier aplicación web: Inyección SQL y Cross-Site Scripting.  […]

  2. […] Parámetros de entrada. Ese gran agujero de seguridad por el que se cuelan dos de las vulnerabilidades más comunes en cualquier aplicación web: Inyección SQL y Cross-Site Scripting. No están por cas…  […]