H E R R A M I E N T A S A V A N Z A DA S D E S O F T WA R E 2 0 0 7-2 0 0 8 DE S A R R O L L O D E S E G U R I DA D E N A P L I C AC I O N E S W E B XSS Y SQL INJEC TION GRUPO 24 SARA EGUILUZ GARBIÑE LÓPEZ IGARKI SAN MILLAN CARMEN RODRIGUEZ S E G U R I D A D E N A P L II COANCE S WEB IND ICE XSS 3 ¿EN QUÉ CONSISTE UN ATAQUE XSS? DIRECTO INDIRECTO BASADO EN DOM ¿CÓMO SE PUEDEN EVITAR? 3 3 3 6 7 SQL INJECTION 9 ¿EN QUÉ CONSISTE UNA INYECCIÓN SQL? ¿CÓMO SE PUEDEN EVITAR? 2 9 11 XSS Referencias utilizadas http://www.cgisecurity.com/articles/xss-faq.shtml http://en.wikipedia.org/wiki/Cross-site_scripting http://es.wikipedia.org/wiki/Cross_Site_Scripting http://www.webappsec.org/projects/threat/classes/crosssite_scripting.shtml http://www.webappsec.org/projects/articles/071105.shtml#r1 ¿EN QUÉ CONSISTE UN ATAQUE XSS? XSS es el acrónimo utilizado para referirse a un tipo de ataque (también a la debilidad de seguridad que permite dicho ataque) denominado originalmente “Cross-Site Scripting”1. Este tipo de ataques se realiza sobre aplicaciones que utilicen HTML (normalmente sitios web). Su nombre podría ser traducido como scripting inter-sitios y se refiere al fundamento de este ataque: inyectar código de script en un sitio web desde otro. Se han documentado tres tipos de ataques XSS: Directo Indirecto Basado en el DOM DIRECTO Denominado en textos de lengua inglesa reflected o non-persistent. Este tipo de ataques se dan cuando datos proporcionados por un cliente web (a través de una URL, de un formulario, etc.) son inmediatamente utilizados por scripts de servidor para generar una página de resultados para dicho cliente web. Si estos datos no son validados y son automáticamente incluidos en la respuesta del servidor, el cliente puede inyectar código (normalmente malicioso) en dicha respuesta. En un principio puede parecer que un cliente puede inyectar código solo en respuestas dirigidas a sí mismo (¡vaya ataque!), pero si dicho usuario “malicioso” crea una URL con código de script y logra que otro usuario acceda a ella, puede lograr que dicho código se ejecute en la respuesta proporcionada al otro usuario. Para enmascarar este tipo de ataques se suele codificar en hexadecimal el código de script (para que el usuario “inocente” no perciba nada extraño). INDIRECTO También conocido como inyección HTML. Denominado en textos de lengua inglesa Persistent o stored. Con objeto de no confundir sus siglas con las hojas de estilo en cascada (Cross Site Scripting = CSS), se cambió la primera letra por la X (cross=cruz). 1 3 Este tipo de ataques se dan cuando los datos proporcionados por los clientes web son almacenados en el servidor (en una base de datos, sistema de archivos, variable de sesión, etc.) y mostrados posteriormente en otra página web del servidor. Ejemplo En la aplicación del laboratorio utilizamos valores introducidos por el usuario a la hora de registrarse almacenados en la base de datos como contenido de, por ejemplo, etiquetas de un formulario. En la clase que mostramos a continuación utilizamos el valor de pregunta de seguridad del usuario almacenado en la base de datos para asignar el valor a una etiqueta de texto: Partial Class CambiarPassword Inherits System.Web.UI.Page (…) Protected Sub BBuscar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles BBuscar.Click Dim username As String = Membership.GetUserNameByEmail(CTEmail.Text) Dim muser As OdbcMembershipUser = Membership.GetUser(username) (…) EPreguntaShow.Text = muser.PasswordQuestion (…) End Sub Esto provoca que, si el usuario a la hora de hacer su registro introduce valores “maliciosos” en el campo de la pregunta de seguridad cuando quiera modificar su password y pulse sobre el botón BBuscar se introducirá como valor de la etiqueta correspondiente el código malicioso, que se ejecutará cuando el usuario cargue la página. <script>alert("Esto es lo que puedo hacer con xss")</script> Existe una directiva de página de ASP que permite validar las peticiones de los clientes (request), por si estas contuvieran contenido sospechoso. Si activamos esta directiva de pagina (validateRequest=”true”) obtendríamos la siguiente salida (una 4 excepción que podemos capturar para que el cliente “malicioso” no tenga noticia de que le hemos descubierto): Si deshabilitamos dicha opción obtenemos la siguiente salida: Podemos comprobar que el código malicioso ha sido almacenado en la BD: Si el usuario accede a la opcion de cambiar contraseña proporcionando su email y pulsando el botón BBuscar (comprobar)… 5 …obtiene la siguiente página (el código de script se ha ejecutado): Para ver lo práctico (en cuanto a “malas intenciones”) de este ejemplo pensemos en: Que el dato introducido por el usuario “con malas intenciones” es un dato que el usuario introduce en la bd y que posteriormente otros muchos usuarios recuperan de manera inconsciente a través de sus peticiones a un sitio web (un post en un foro, por ejemplo). Que el script no se limita a una alerta, sino que es un script que, por ejemplo, recoge una cookie de autenticación de sesión y la reenvía a otro usuario. BASADO EN DOM A diferencia de los dos tipos de ataque XSS anteriores, el código malicioso no se ejecuta porque el servidor devuelva una respuesta HTML con dicho codigo embebido, sino porque el cliente comienza a parsear un árbol DOM utilizando datos entre los que se encuentra dicho código (por ejemplo, utilizando la URL actual del documento document.URL que incluye un script malicioso). 6 ¿CÓMO SE PUEDEN EVITA R? La forma más efectiva de evitar los tipos de ataques XSS se basa en el principio “no confíes nunca en el usuario”. Filtrar el contenido de las peticiones del cliente en busca de caracteres “sospechosos” y traducirlos a sus entidades HTML correspondientes (convertir < y > a &lt; y &gt;) para generar código HTML valido es de gran utilidad (sin embargo esto supone un mayor tiempo de proceso de la petición). Este tipo de técnica es la que aplica ASP por defecto, como se ha visto con anterioridad. Como medida adicional es aconsejable revisar el contenido de las respuestas generadas en el servidor que utilicen datos introducidos por el usuario o procedentes de una base de datos (variables de sistema como las de sesión también son susceptibles de manipulaciones de este tipo). En ASP esto se puede conseguir a través de los métodos UrlEncode y HttpEncode de la clase HttpUtility. Ejemplo Si en el ejemplo anterior el servidor realiza una traducción de los símbolos “sospechosos” y los traduce a sus entidades HTML correspondientes el valor almacenado en la base de datos pasaría a ser el que se muestra a continuación: Y, por tanto, la respuesta obtenida al intentar modificar la password sería la mostrada a continuación: 7 Para evitar los ataques basados en DOM es aconsejable: 1. Evitar realizar redirecciones o reescribir parte del documento en el cliente utilizando datos del cliente. 2. Analizar el código del lado del cliente, de manera que las referencias a objetos DOM que puedan ser manipuladas por el usuario deberían ser inspeccionadas (por ejemplo: document.URL, document.location, etc.). 8 SQL I NJE CTIO N Referencias utilizadas http://en.wikipedia.org/wiki/SQL_injection http://www.webappsec.org/projects/threat/classes/sql_injection.shtml http://www.securiteam.com/securityreviews/5DP0N1P76E.html http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnsqlmag04/html/InjectionProtection.asp ¿EN QUÉ CONSISTE UNA INYECCIÓN SQL? Al igual que XSS, el término “inyección SQL” se refiere tanto al tipo de ataque realizado como a la vulnerabilidad que permite realizarlo. La inyección SQL permite a un usuario ejecutar codigo SQL “de cosecha propia” (normalmente con fines ilícitos) enmascarándolo o camuflándolo dentro de código SQL utilizado en una aplicación para realizar las tareas que correspondan al comportamiento habitual de ésta. Este codigo enmascarado se ejecutará en la base de datos con los mismos permisos con los que se ejecute el código que lo contiene. Ejemplo 1 Public Shared Function obtenertipo(ByVal email As String) As OleDbDataReader Dim st = "select tipo from usuarios where Email='" & email & "'" comando = New OleDbCommand(st, conexion) Return (comando.ExecuteReader()) End Function Si el parametro email es una cadena de texto como la que siguiente (suponemos que pepe@pepe.com es un email valido registrado en la base de datos): pepe@pepe.com'; SELECT * FROM usuarios WHERE email LIKE '% Lograríamos ejecutar en la base de datos las siguientes consultas SQL: select tipo from usuarios where Email='pepe@pepe.com' SELECT * FROM usuarios WHERE email LIKE '%' Es decir, podriamos seleccionar todos los datos de todos los usuarios de la base de datos. Ejemplo 2 Public Shared Function comprobarpassword(ByVal email As String) As OleDbDataReader 9 Dim st = "select contraseña from usuarios where Email='" & email & "'" comando = New OleDbCommand(st, conexion) Return (comando.ExecuteReader()) End Function Si el parametro email es una cadena de texto como la que siguiente (suponemos que pepe@pepe.com es un email valido registrado en la base de datos): pepe@pepe.com' or 't'='t Lograríamos ejecutar en la base de datos las siguientes consultas SQL: select contraseña from usuarios where Email='pepe@pepe.com' or 't'='t' El resultado de la segunda condicion del or es 1, por lo que el mismo se evalua siempre a true, ejecutando la sentencia, lo que nos permite seleccionar la contraseña del usuario que elijamos. Las inyecciones SQL permiten también obtener información de la base de datos a la que no estamos autorizados a acceder. Ejemplo 3 Si conseguimos ejecutar una sentencia como la siguiente (ver ejemplos 1 y 2 para mas información sobre como conseguirlo): SELECT 1/0 FROM usuarios WHERE email='pepe@pepe.com' En primera instancia se ejecuta la segunda parte de la consulta (from usuarios where…), por lo que la selección solo se realizará si existe un email en la tabla pepe@pepe.com. Como la seleccion es una división entre cero y ésta genera un error la consulta en su totalidad generará un error si y sólo si existe un email en la tabla usuarios pepe@pepe.com. Un atacante puede servirse de esta clase de ataques para averiguar si existen ciertos campos en la base de datos. Sin embargo ASP (mas exactamente el objeto OleDbCommand) controla que haya caracteres de final de sentencia ( y otros caracteres especiales) y bloquea la ejecución de los comandos mostrados en los ejemplos anteriores, como se muestra a continuación. 10 ¿CÓMO SE PUEDEN EVIT AR? Referencias utilizadas http://msdn2.microsoft.com/en-us/library/ms998271.aspx Al igual que con los ataques XSS, la forma más sencilla de evitar los ataques por inyección SQL es aplicar la máxima “no confíes nunca en el usuario”, realizando filtrados sobre la entrada del usuario, los parámetros de las URL y los valores de las cookies en busca de caracteres como las comillas simples, barras, barras invertidas, puntos y coma, caracteres especiales como los retornos de carro, nuevas líneas, etc. En ASP es posible denegar al usuario la introducción de estos caracteres utilizando validadores de campos de introducción de datos basados en expresiones regulares (ver la referencia indicada al principio de la sección). Al ejecutar sentencias en la base de datos que utilicen información proporcionada por el usuario es aconsejable utilizar sentencias parametrizadas que nos permiten restringir el tipo de dato que utilizamos e incluso la longitud de los mismos, como se muestra a continuación. Ejemplo consulta = "select tipo from usuarios where Email=@email" Dim comando As New OleDbCommand(consulta, conexion) comando.Parameters.Add("email", OleDbType.VarChar, 15) con lo que solo admitiriamos valores string de longitud 15 para el campo email, pudiendo utilizar procedimientos análogos para valores numéricos, por ejemplo. 11