sábado, abril 07, 2007

SQL Injection

Hace ya como 6 meses había yo mencionado un problema de SQL injection en un sitio publico del ITT - por cierto la ultima vez que lo revise en Diciembre, aun y cuando yo ya lo reporte, sigue con el mismo problema -, bueno pues hoy leyendo este weblog me encontré que mencionaban una vulnerabilidad en un nuevo sitio de la Secretaria de Seguridad Publica del DF - lanzado apenas el dia de ayer - donde se presenta un problema de SQL Injection también, el único problema es que alguien ya encontró como explotarlo y el sitio esta inaccesible.



Nota: Parece que ya repararon el sitio de la SSP, pero la vulnerabilidad aun esta presente.

Es realmente critico que empresas y dependencias de gobierno usen desarrolladores inexpertos para crear sitios web - quizás porque cobran mas barato? - con errores tan increíbles como la construcción de sentencias de SQL con strings, dejando COMPLETAMENTE vulnerable el sitio y la información alojada en el. Ambos sitios - el del ITT y el de la SSP - usan MS SQL Server y ASP (clásico y ASP.NET), pero en este caso definitivamente el problema no es una vulnerabilidad ni del sistema operativo, ni del servidor de la base de datos, ni de ASP, el error es un grave error de diseño y definitivamente la falta de experiencia.

Pero que es una inyección de SQL?, bueno es un forma de explotar el acceso no autorizado a servicios o a datos de un sitio Web, en donde se envían instrucciones de SQL en algunos de los campos de captura, por ejemplo de un formulario, para tratar de que estos se ejecuten en la base de datos del sitio Web y con ellos ganar el acceso buscado.

Por ejemplo, uno de los errores mas comunes que expone este tipo de vulnerabilidad es el crear sentencias de SQL como simple strings dentro del programa, en donde si hay que pasar valores de variables al SQL, estos se pasan concatenado el SQL con la variables que contienen dichos valores, ej:

string usuario = "minombre";
string clave = "miclave";

string sql = "SELECT nombre FROM usuarios WHERE usuario = '" + usuario + "' AND clave = '" + clave + "'";

Aquí el sql es construido dinámicamente para validar que el usuario existe con la clave correspondiente, si suponemos que las variables usuario y clave están ligadas a los textboxes donde el usuario captura esa información, alguien podría "inyectar" otras instrucciones de SQL para lograr acceso, ej:

string usuario = "minombre";
string clave = "miclave' OR 'X' = 'X";

string sql = "SELECT nombre FROM usuarios WHERE usuario = '" + usuario + "' AND clave = '" + clave + "'";

Con "' OR 'X' = 'X" que le agregue a la clave, me aseguro que si el nombre de usuario o la clave están incorrectas, el query si va regresar algún registro y muy posiblemente la lógica del programa me va a permitir tener el acceso que busco.

El problema mayor proviene que si se captura alguna secuencia de caracteres para generar un error en el SQL, los programadores descuidados van a mostrar el mensaje de error completo, el cual muchas veces provee el nombre del servidor, información sobre el motor de bases de datos usado, información sobre la tabla de usuarios, etc, dejando la puerta abierta para que alguien con un poco de malicia pueda causar grandes daños que pueden implicar la caída del servidor, el robo de datos o el borrado de información.

La forma de protegerse de este tipo de ataques realmente es muy sencilla, lo primero es evitar a toda costa usar instrucciones de SQL dinámicas concatenando valores, por ejemplo con ADO.NET se puede hacer algo como:

SqlCommand cmd = new SqlCommand();
cmd.Text = "SELECT nombre FROM usuarios WHERE usuario = @usuario AND clave = @clave";

SqlParameter param1 = cmd.Parameters.Add("@usuario");
param1.Value = "minombre";

SqlParameter param2 = cmd.Parameters.Add("@clave");
param2.Value = "miclave";

De esta forma sencilla ya se esta evitando la posible inyección de SQL en nuestro servidor, adicionalmente es recomendable que el usuario con el que la aplicación Web se conecta a la base de datos, tenga los mínimos privilegios sobre la base de datos (no usar el usuario sa), si es posible, es todavía mejor usar Stored Procedures ya que estas ofrecen un mayor nivel de seguridad al realizar la función exclusiva para la que están programadas y el usuario que se use para conectarse a la base de datos, no necesita de privilegios para insertar, actualizar o eliminar en las tablas utilizadas por la aplicación; finalmente si es un servidor de producción, poner un manejador de errores global en la aplicación para que muestre una pagina amigable informando al usuario de que existió un error en la aplicación, y que no muestre información critica del error, el cual puede ser enviado mediante una alerta al administrador o bien guardado en una bitácora.

No hay comentarios.: