SQL Injections es una técnica por la cúal un atacante de una página Web es capaz de acceder a nuestra base de datos y ejecutar sentencias SQL sobre ella.
La técnica se basa en aprovechar las páginas con formularios de toma de datos (logins, busquedas ...) para montar sentencias SQL que se ejecutaran en el servidor aprovechando los errores comunes de programación en los entornos Web.
El escenario sobre el que vamos a desarrollar el articulo es una página de login que dará acceso a la zona privada de la Web. Esta página solicitará el nombre de usuario y password de acceso. El código de la página está escrito en ASP, pero debemos tener claro que SQL Injections no es una vulnerabilidad de ASP, sino que cualquier página PHP, JSP, ASP.NET, CGI ... es susceptible de recibir este tipo de ataques.
El siguiente código html ilustra la página de entrada de datos, la página se guardará con el nombre frmLogin.html:
<html> <body> <form name="frmLogin" action="login.asp" method="post"> <table align="center" border="1" > <tr> <td align="center" colspan="2"><b> Datos de Acceso </b> </td> </tr> <tr> <td>Usuario:</td> <td><input type="text" name="usrtxt" ID="Text1" /></td> </tr> <tr> <td>Password:</td> <td><input type="text" name="pwdtxt" ID="Text2" /></td> </tr> </table> <p align="center"><input type="submit" value="enviar" ></p> </form> </body> </html> |
En este ejemplo hemos dejado el campo password (pwdtxt) como texto normal, para poder ver que es lo que tecleamos.
Los datos se envian a la pagina login.asp, que recoge los parámetros de la página frmLogin.html, y consulta nuestra base de datos para comprobar si el nombre de usuario y password es correcto. La base de datos podría tener los datos que muestra la imagen.El codigo de login.asp sería así:
<% Option Explicit Dim strLogin, strPassword, strSQL Dim connection, rs strLogin = Request("usrtxt") strPassword = Request("pwdtxt") strSQL = " SELECT * FROM USUARIOS " & _ " WHERE USUARIO='" & strLogin & "' AND " &_ " PASSWORD='" & strPassword & "'" Set connection = Server.CreateObject("ADODB.Connection") connection.Open "DRIVER={SQL Server};SERVER=SERVIDOR;" _ & "Database=DBNAME;User Id=USER;password=CLAVE" Set rs = connection.Execute(strSQL) If( Not rs.EOF ) Then Response.Write("Indentificacion correcta") else Response.Write("Indentificacion INCORRECTA") End If rs.Close connection.Close Set rs = Nothing Set connection = Nothing %> |
Esta sería una página totalmente normal que cualquier desarrollador medio podría haber desarrollado. Existen miles de páginas como ésta (y peores) colgadas en Internet, en ocasiones como única "guardia" de datos valiosos.
El funcionamiento de la página es simple, se conecta a la base de datos, ejecuta la consulta contra la base de datos y nos valida o invalida el acceso. Sencillo.
Supongamos que el usuario llega a su formulario de identificación, e inserta los datos "Devjoker" como identificación y "secreta" como contraseña. Por tanto, la cadena SQL que ejecutaría la página sería como esta:
SELECT * FROM USUARIOS WHERE USUARIO='Devjoker' AND password='secreta' |
Para entender el ataque hay que tener dos conceptos previos:
- SQL no utiliza comillas dobles para los valores de texto, sino comillas simples.
- Los comentarios en lenguaje SQL se escriben con un doble guíon "--".
En la casilla Login, se escribiría un valor cualquiera, por ejemplo "usuario", y en la casilla Password, escribiríamos lo siguiente : 'or 1=1 --.
El formulario de entrada de datos quedaría del siguiente modo:
Usuario:USUARIO_CUALQUIERA
Clave:' OR 1=1 --
El resultado es que el sistema nos da acceso ...
¿Que ha pasado?¿Porque ha dado como válido el usuario y la contraseña si en realidad no lo son?
Cuando la página login.asp forma su sentencia SQL, concatena los valores que hemos enviado desde frmLogin.html. La primera comilla simple que hemos tecleado en el campo password hace que se cierre la cadena, y se añade una cláusula OR que siempre será cierta (1=1). Además, para prevenir que el sistema dé un error, ya que todavía quedaría una comilla simple sin cerrar, se añade el símbolo del comentario en SQL, que hace que el sistema no haga caso al resto de la cadena SQL.
La sentencia SQL que finalmente ejecutaría el servidor es:
SELECT * FROM USUARIOS WHERE USUARIO = 'usuario' AND PASSWORD ='' OR 1=1 --' |
Como resultado de la ejecución de esta consulta tendremos acceso a la zona privada. En realidad da lo mismo lo que pongamos en el campo usuario, ya que la segunda condición se cumple siempre y se especifica con un operador OR.
El uso de nombres de usuario previsibles, tales como "Admin" o "Administrador" es otra puerta abierta. Si tecleamos "Admin" como usuario, la query quedaría del siguiente modo ...
SELECT * FROM USUARIOS WHERE USUARIO = 'ADMIN' AND PASSWORD ='' OR 1=1 --' |
Pero la peor parte de este tipo de ataques esta por llegar. Algunos gestores de bases de datos son capaces de ejecutar mas de una sentencia SQL, separadas por punto y coma. Por lo que si sabemos cual es el nombre de una tabla podríamos ejecutar sentencias SQL con la intención de borrar los datos o la propia tabla.
En el siguiente ataque el usuario introduce los siguientes valores:
Usuario:Pedro
Clave:' HAVING 1=1 --
La sentencia SQL que se compone es la siguiente:
SELECT * FROM USUARIOS WHERE USUARIO = 'ADMIN' AND PASSWORD ='' HAVING 1=1 -- |
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'USUARIOS.CO_USUARIO' is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.
El error nos esta informando de que la tabla se llama USUARIOS, por lo que ahora podemos escribir lo siguiente en el formulario de entrada:[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'USUARIOS.CO_USUARIO' is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.
Usuario:Pedro
Clave:' ; DROP TABLE USUARIOS ; --
Con esta ejecución el usuario ha conseguido eliminar nuestra tabla de usuarios ...
Como protegerse de este tipo de ataques.
Para protegerse de este tipo de ataques podemos (y debemos) tomar varias medidas.
- Parametrizar las consultas utilizando comandos preparados. Con esto conseguimos evitar la ejecución de código no deseado. Es la mejor forma de protegernos. En muchos articulos recomiendan "reemplazar" las comillas simples y otros caracteres "peligrosos", pero este método es mucho mas seguro y fácil de implementar.
<% sql = "Select * from USUARIOS where USUARIO=? and CLAVE=?" set cmd = Server.CreateObject("ADODB.Command") cmd.ActiveConnection = connection cmd.CommandText =sql cmd.Parameters(0).Value = usuario cmd.Parameters(1).Value = clave set rs = cmd.Execute() %> |
- Conectar a la base de datos con usuarios que solo tengan permisos de lectura, de esta forma el atacante no tendrá permisos de ejecución. Esta es una tarea que debe realizar el DBA, y debemos tener usuarios de solo lectura para aquellas partes de nuestra aplicación que pensemos que pueden ser victimas de ataques.
No hay comentarios:
Publicar un comentario