jueves, 12 de mayo de 2011

SQL Injections - Inyecciones SQL.

Seguridad en Internet.
 



    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' 
    Este es el funcionamiento esperado, pero un atacante podría introducir ciertos valores que alteren este comportamiento ....      

    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 "--".
    Con estas premisas resulta sencillo "cerrar" la cláusula SQL que creemos que el servidor va a ejecutar mediante los valores que introducimos en la página frmLogin.html.
    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 --'
    Si se produce este caso, no solo tenemos acceso al sistema sino que además tendremos privilegios de administrador.
    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 --
    La sentencia SQL que ha quedado formada es incorrecta, por lo que la ejecución fallará y se devolverá el error correspondiente, en nuestro caso seria el siguiente:
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:
              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

free counters