[Indice]


La seguridad, esa gran desconocida

Este es un tema que no suele tratarse en los manuales técnicos. Generalmente se le considera una cuestión de empresa, pero como buena parte de la seguridad de los datos dependerá de aspectos puramente técnicos o de programación, lo veremos aquí brevemente (muy brevemente, ya que esto es toda una profesión en sí misma).

Son dos los aspectos que deben contemplarse en cuanto a la seguridad de los datos. El primero es su custodia, y el segundo garantizar la permanencia física de los mismos. Es decir, hay que evitar que personas no autorizadas accedan a los datos, y al mismo tiempo hay que mantener los sistemas de forma que éstos no se pierdan.

Respecto a lo primero, ante todo hay que dejar una cosa clara: nuestra responsabilidad. En efecto, cuando se recogen datos de personas por el medio que sea, y con su conocimiento o sin él, si éstos terminan en un fichero informático, estamos obligados ante la Ley (por lo menos en Europa) a proteger esos datos, y por supuesto, no estamos autorizados a utilizarlos para ningún fin distinto del que se manifiesta cuando se recaudan, ni a cederlos a nadie.

Aclarado este punto, surge la pregunta: ¿qué se puede y/o debe hacer para proteger los datos? La respuesta no depende solamente del programador; la empresa tiene mucho que decir en esto, y desafortunadamente, la mayoría de las veces no dice nada porque no tiene ni idea de tales menesteres. En ese caso, es el programador quien debe plantear la conveniencia de establecer una política de seguridad de los datos de la empresa, y es ésta la que debe implantar los protocolos de actuación correspondientes.

Desde el punto de vista práctico, en la protección de datos pueden considerarse dos grandes bloques, ambos de la misma importancia, y será el conjunto el que nos brinde, hasta donde ello es posible (recuerda, no hay sistema totalmente seguro), un cierto nivel de protección.

Seguridad hardware

Evidentemente, es el servidor donde físicamente residen los datos el primer elemento que hay que proteger. Por muchas medidas de seguridad que se establezcan, no servirán de mucho si resulta que el servidor está accesible a cualquiera. Hay máquinas de usuario mucho mejor protegidas que el servidor corporativo de algunas empresas.

La primera precaución es que un servidor, como su nombre indica, se debe dedicar a eso, a servir datos, no a ser la estación de trabajo de media oficina... o de toda ella. Eso significa que solamente unas pocas personas deberían tener acceso físicamente a él (el jefe, el administrador, y pocas más). Esta dedicación exclusiva del servidor, además de proporcionar una mayor seguridad de los datos, hará que el rendimiento de la máquina sea muy superior.

Otro eslabón de la cadena de seguridad hardware debería ser un elemento frecuentemente olvidado, y que se suele echar en falta cuando ya es demasiado tarde: un SAI (Sistema de Alimentación Ininterrumpuda -UPS- en inglés). En efecto, un servidor, si no está protegido eléctricamente, está muy expuesto a sufrir una grave avería, y puede dejar colapsada la empresa si falla. Si la causa es un pico de tensión, o una descarga estática por una tormenta, puede incluso quemarse el servidor, o un disco, o la fuente de alimentación, o... Si se trata de un apagón no programado (que suelen ser casi todos), Murphy se encargará de que el corte pille al servidor en mitad de varias transacciones, que al apagarse la máquina inesperadamente dejará varias tablas de nuestras bases de datos corruptas, o con índices truncados. Cuesta horas recomponer desastres así, y a veces no es posible recuperarlos por completo.

Conviene calcular bien la potencia y autonomía necesarias (ver estadística de apagones en la zona si es posible) antes de adquirir el SAI, y es preferible que el servidor de datos tenga uno para él solo, o como máximo, compartirlo con el servidor web, si lo hay. El SAI no debe limitarse sólo a mantener la alimentación durante un cierto tiempo. Si el apagón es prolongado, tarde o temprano el SAI se agotará y tendremos el mismo problema que si no hubiese SAI. Se debe instalar un SAI que pueda conectarse a algún puerto físico del servidor y enviarle una señal de apagado (shutdown) cuando haya transcurrido el tiempo de autonomía del SAI, a fin de que el sistema pueda cerrar ordenadamente los procesos que tenga en marcha, y se apague por sí mismo.

Generalmente, los servidores suelen estar funcionando las 24 horas del dia, y está comprobado que las máquinas que no se apagan nunca sufren menos averías que las que se desconectan varias veces cada día. Para garantizar una larga vida al servidor, es importante que esté en un lugar limpio de polvo, seco y fresco. Lo del polvo es muy importante, ya que éste es aspirado por los ventiladores hacia el interior, y se depositará en los disipadores de los procesadores, reduciendo la disipación calórica, incluso puede acabar bloqueando los ventiladores, lo que probablemente provocará una costosa avería. Es buena idea hacer periódicamente un chequeo del estado físico del servidor, y si es necesario, proceder a su limpieza. OJO limpiar siempre por aspiración o soplado, no con brocha, y siempre con la máquina apagada. Otra cosa importante es que el servidor no debe estar en el suelo, donde aspirará más polvo, y estará más expuesto a recibir golpes o a mojarse. Si la máquina es movida o recibe un golpe estando en marcha, los más probable es que los discos te recuerden que eso no debe hacerse.

A pesar de todas nuestras precauciones globales, al servidor le puede fallar un elemento interno, como un disco o la fuente de alimentación (el más frecuente). Conviene tener siempre repuestos de estos dos elementos, así como de los ventiladores de los radiadores de los procesadores. Si un disco falla, evidentemente, los datos que contiene se pierden. Ante esto solamente hay una solución: tener copias de seguridad. Es increible la cantidad de gente que no hace copias regularmente de sus datos... hasta que ocurre lo que tarde o temprano tiene que ocurrir. Recuerda que los discos tienen un tiempo limitado de trabajo, que aunque suele ser muy alto, puede ser radicalmente reducido si las condiciones de trabajo no son las adecuadas.

Dependiendo de lo críticos que sean los datos, además de copias regulares (cada dia por lo menos), es buena idea montar los servidores desde el principio con sistemas tolerantes a fallos. Un método ideal es que el disco principal, donde esté el sistema y las bases de datos, tenga RAID-1 (Redundant Array of Independents Disks). Esta técnica consiste en montar dos discos idénticos, donde uno se constitute en espejo del otro, de forma que si cualquiera de ellos falla, automáticamente el sistema continúa funcionando con el segundo. En ese momento, el sistema advierte de que el espejo se ha roto, y si hemos tenido la precaución de adquirir un recambio, el tiempo de parada será mínimo (nulo si el servidor soporta remoción de discos en caliente) y no se producirá ninguna pérdida de datos. La técnica RAID puede montarse mediante placas base que la soporten en su propia BIOS, o con placas controladoras adicionales. Si no se puede disponer de RAID hardware, también hay sistemas operativos de servidor que pueden hacer lo mismo mediante software, aunque es algo menos eficiente, para instalaciones pequeñas/medianas, servirá perfectamente. Es buena idea tener discos de recambio, todos del mismo modelo, ya que pasados algunos años (no muchos) será difícil encontrarlos, y más con prisas. El que sean del mismo modelo tiene mucha importancia si el RAID montado es controlado por placa hardware. Si el RAID es controlado por software no suele ser tan importante que no sean iguales. No olvides poner etiquetas físicas a cada disco con el número que el sistema le asigna(0, 1, 2, etc.) Si se rompe un espejo, tendrás dificultades para saber cuál es el defectuoso.

Al margen de tener instalado RAID o no, las copias de seguridad (backup) se deben hacer, y evidentemente, se deben hacer en otro disco distinto, bien en el mismo servidor o en otra máquina. El problema de optar por otra máquina es que tiene que estar encendida cuando se hagan los backups, que suelen hacerse a horas intempestivas, que esa máquina debe observar las mismas precauciones de seguridad que el propio servidor y que, preferentemente, debe estar dentro de la intranet, ya que si hay una caída de la red exterior, ese día no se haría del backup. Se deben hacer copias de seguridad, tanto del sistema como de las bases de datos. Es buena idea tener otra copia de seguridad fuera del edificio donde resida el servidor, ya que en caso de incendio o robo podríamos perder tanto el servidor como las copias. Recordar que esa copia de seguridad (como todas) debe estar, a su vez, bien protegida y actualizada regularmente.

Si haces copias de seguridad sobre CDROM, DVD o cintas, puede que alguna vez la copia falle, y el soporte no sea legible. Hay quien tira a la papelera el disco o cinta defectuosos sin mayores precauciones. CUIDADO: Con los programas adecuados se pueden extraer datos de esos soportes.

Seguridad software

El primer eslabón de esta otra cadena es crear una política de contraseñas realmente efectiva, con permisos estructurados y gestión de grupos, donde cada usuario sólo tenga acceso a aquello que le compete, y sea consciente de su responsabilidad y obligación de proteger su clave de acceso. He visto sitios donde la clave de acceso estaba escrita en un "postit" pegado en la pantalla, o vocear en medio de una sala llena de gente: "¿Cual es la clave de esta semana?.." Lo peor es que contestaron.

Así mismo, el servidor debe tener instalado un buen cortafuegos (firewall) que no permita conectarse más que a las máquinas de la empresa. Desde el servidor no se debe navegar por internet, ni siquiera leer el correo, y si esto se cumple, prácticamente no será necesario instalarle un antivirus, que actualmente suelen ralentizar bastante el funcionamiento de las máquinas. Si no se le instala antivirus, hay que tener presente que existen virus que se transmiten a través de discos removibles y memorias flash conectados a los puertos USB, por lo que se deben verificar esos dispositivos si se utilizan para introducir datos en el servidor, y asegurarse de que están "limpios".

El servidor de datos no debe permitir conexiones de nadie que no esté dentro de nuestra red local (intranet), y por supuesto, jamás será servidor web al mismo tiempo que servidor de datos. Solamente el servidor web, que debe ser otra máquina diferente, dialogará con el exterior, y también tendrá su correspondiente cortafuegos.

Tanto en el servidor de datos como en el servidor web, se deshabilitarán todos los servicios que no sean necesarios, como TELNET, FTP, SNMTP, HTTP, o los que procedan en cada caso, sin olvidar los de escritorio remoto. En suma, se trata de que todos los puertos que no tengan una utilidad permanente en el servidor, estén debidamente cerrados, o mejor, ni siquiera instalados aquellos programas que no tengan utilidad declarada. Siempre será más fácil vigilar un edificio con un par de puertas, que otro con cientos de ellas, y además abiertas.

La inmensa mayoría de pérdidas de datos debidas a infecciones de virus o ataques de hackers (piratas informáticos) los provoca o facilita en gran manera el propio usuario de la máquina, al tener multitud de puertos TCP abiertos inútilmente, abrir adjuntos de e-mail sospechosos, navegar por páginas web que inspiran poca o ninguna confianza, o instalar programas de dudosa utilidad y nula garantía de seguridad (hay mucho freeware asesino por ahí). Si a esto añadimos que algunos sistemas operativos (y en especial su navegador) son una especie de colador de colores, lo raro es que nuestros datos no terminen en manos del primer aficionado a hacker que pase por allí.

Aunque pueda parecer obsesivo, un buen administrador de sistema debe estar permanentemente en alerta con los servidores a su cargo. Recuerda que en la actualidad, en general, los atacantes no persiguen borrar tus datos, esas son técnicas del pasado, si no conseguir el acceso a la máquina y permanecer en el más absoluto anonimato. Lo que persiguen requiere discreción, y tanto si consiguen un acceso como inyectar un virus o un troyano, intentarán permanecer invisibles el mayor tiempo posible. La finalidad de todo es robar datos, claves de acceso o utilizar la máquina como "zombie" para lanzar desde ella ataques a otras máquinas.

Seguridad en servidores web

Son muchas las aplicaciones que, inicialmente, se diseñan para trabajar en local y por tanto con niveles muy bajos de seguridad (a veces inexistentes por completo), que terminan siendo parte de otra con conexiones a internet o a redes externas, donde los requerimientos de seguridad son infinitamente más altos que en redes locales. Estas ampliaciones sin incluir módulos de seguridad, representan un grave peligro para los datos, y deben mejorarse cuanto antes. Recuerda que un ataque desde el exterior, generalmente, no se debe a que tus datos sean más o menos interesantes para alguien, sino al simple y fortuito hecho de que un hacker localice tu máquina y advierta que es vulnerable. La tentación será irresistible...

Hay muchas formas de intentar extraer datos de un servidor web, pero para todas ellas, salvo agujeros graves de seguridad del sistema operativo o del programa servidor, el atacante necesita conocer un usuario válido y su clave de acceso. Y a eso dedicará todos sus esfuerzos. El eslabón más débil de la cadena son los propios usuarios. En efecto, casi siempre que lo consiguen es debido al poco cuidado que los usuarios autorizados tienen con sus contraseñas. A nadie se le ocurre dejar las llaves de su casa puestas en la puerta, y si las pierde, se apresurará a cambiar la cerradura por si acaso... pero esas elementales precauciones no se tienen cuando de accesos informáticos se trata. ¿Por qué? misterios de la naturaleza humana.

Así pues, además de cuidar con esmero las claves de acceso, lo primero que debemos hacer es cerrar todas las puertas que no sean necesarias del servidor. En un servidor web lo típico necesario suele ser el propio servicio HTTP (puerto 80), y tal vez, el de FTP (puertos 20 y 21). Una herramienta fundamental para conseguir esto es instalar un buen programa firewall (cortafuegos), o utilizar el propio del sistema operativo, si lo tiene, y configurarlo de modo que no se pueda accecer a ningún puerto que no sean los mencionados. Tampoco es mala idea deshabilitar todos los protocolos de comunicaciones que no sean de verdad necesarios, como el UDP, y dejar solamente el TCP. Si hay algún otro servicio instalado, pero que no es de uso público, conviene restringir el acceso filtrando el número IP o la dirección MAC de las tarjetas de red de las máquinas autorizadas, y bloquear todas las demás. Si el firewall dispone de temporizador, es interesante establecer un horario de acceso y bloqueo: Muchos ataques se producen cuando no hay nadie en la empresa vigilando la actividad del servidor, y si no hay nadie, es perfectamente inútil tener abierto el acceso de otras máquinas de la empresa al servidor. El único que puede necesitar permiso de acceso todo el dia suele ser el servidor web.

El siguiente paso será limitar los privilegios del usuario por defecto (anonymous) que los servidores suelen utilizar para responder a las llamadas del exterior. Este usuario genérico solamente debe tener permisos de lectura en el área donde residan los datos del web, y ocasionalmente, permisos de ejecución de ficheros de comandos u otro tipo de ejecutables, como CGI, servlets, scripts, etc., si los hay. En resumen, se trata de que si alguien consigue entrar en el servidor utilizando ese usuario, no pueda conseguir con él nada distinto de lo que conseguiría operando normalmente con un navegador.

Si tu web utiliza bases de datos, que como ya se ha dicho, deberían estar en otra máquina, NUNCA utilizes el usuario administrador, o un usuario con privilegios altos en tus aplicaciones. Crea un usuario específico para estos fines, que no pertenezca al grupo de administradores, con una clave de acceso buena (por lo menos 10 caracteres alfanuméricos aleatorios), con los privilegios lo más restringidos posible, los justos para que permita operar a la aplicación, y no es buena idea que tenga permisos de borrado, como máximo de modificación. Si hay que borrar algo, que lo haga el administrador personalmente. Y por supuesto, no debe tener permisos que le permitan acceder a tablas del sistema.

Por último, hay que acostumbrarse a revisar periódicamente los ficheros de "loggins" de los servidores y los del firewall, verificando que no ha habido accesos a horas extrañas, ni de máquinas desconocidas, y de vez en cuando, comprobar que todas las políticas de seguridad que hemos programado siguen activas, ya que lo primero que un hacker haría es deshabilitarlas.

De viaje por la red

Una vez configurados los aspectos básicos de seguridad del servidor, nos debemos plantear cómo se moverán los datos por la red. Evidentemente, la decisión a tomar dependerá del tipo de datos de que se trate. No es lo mismo enviar un comentario a un foro, que hacer una compra con tu tarjeta de crédito. Internet es un medio de comunicación muy inseguro debido a la propia estructura de la red. Los datos que viajan entre el cliente y el servidor no se envian en un único paquete, ni viajan directamente de una máquina a otra. Se segmentan en pequeños paquetes que se enrutan a través de un número variable de nodos hasta que llegan a su destino. En cualquiera de ellos se puede leer su contenido, modificarlo o destruirlo, por lo que la confidencialidad puede decirse que no existe. Recuerda que TODO lo que se hace en internet, de una forma u otra deja rastro. La única "protección", si es que se le puede llamar así, que la red ofrece es la enorme cantidad de información que se mueve por ella, lo que dificulta un tanto capturar los datos; no es nada insalvable para un buen hacker, aunque desde luego no con la facilidad que se ve en el cine.

Existen varias técnicas de protección que pueden aplicarse cuando la naturaleza de los datos exige una mayor seguridad. Posiblemente la más conocida es el protocolo SSL (Secure Sockets Layer) diseñado hace ya muchos años por Netscape. Para utilizarlo no es necesario hacer nada especial, simplemente habilitarlo en el servidor (el navegador ya lo detecta automáticamente) instalando un certificado digital de servidor emitido por una Autoridad Certificadora (CA). Al activarlo en el servidor no olvidar abrir el puerto 443 (por defecto) de este servicio en el firewall. La dirección de los servidores que utilizan SSL comienza por https:// en lugar del típico http. Lo que hace SSL es cifrar, con un algoritmo distinto para cada sesión, los datos intercambiados entre el cliente y el servidor, es decir, lo que viaja por la red no es transparente, como hace el protocolo http. Terminada la transacción, los datos se guardan en el servidor sin cifrar.

Aunque muy extendido, SSL es un protocolo de seguridad que fue diseñado para propósitos generales, y no es una solución absolutamente fiable si se requiere gran seguridad, como en el caso de cormercio electrónico con pago. Para este tipo de transacciones se diseñó en 1995 el protocolo SET (Secure Electronic Transaction) , que después de algunas modificaciones se ha convertido en un estándar. Una de las diferencias con SSL estriba en que los datos, además de viajar encriptados por la red, permanecen así también en el servidor, lo que asegura más su confidencialidad aún en el caso de que el servidor sufriera un ataque con éxito.

Si no se desea encriptar la información (que también podría ser interceptada, y con paciencia, descifrada), se puede recurrir a crear una red virtual privada o VPN (en inglés Virtual Private Network). Esto consiste en crear una especie de "túnel" privado directo entre las dos máquinas que establecen el diálogo, de forma que nadie pueda interferir lo que circula por ese túnel. El problema de esta técnica es que el cliente tiene que instalarse una pequeña aplicación que permita establecer esa conexión especial, y aunque no es muy complicado, para algunos usuarios puede ser problemático (como casi siempre que se espera alguna acción del cliente). Además requiere del servidor más recursos para mantener las conexiones activas.

Seguridad en aplicaciones web

Hasta aquí, si se ha aplicado todo lo dicho, puede parecer que ya lo tenemos todo controlado, pero todavía nos queda el último eslabón de la cadena software: la aplicación web con la que va a trabajar el cliente. Evidentemente, si los contenidos de la página son estáticos, pocos problemas pueden generarse, pero si se utilizan bases de datos, la cosa cambia. En efecto, aunque la base de datos utilizada por la aplicación web contenga datos sin importancia, como por ejemplo un libro de visitas, la aplicación hará llamadas al mismo servidor donde podemos tener bases de datos que sí contienen información que debe ser protegida. Dependiendo de cómo se diseñen las aplicaciones web, podemos estar, sin saberlo, dando herramientas a un posible atacante para que llegue a donde no debe. Así pues, por insignificante que pueda parecer la importancia de algunas bases de datos, no deben utilizarse de cualquier manera, ya que indirectamente podría utilizarse el acceso a ellas para obtener información relevante del servidor.

Las primeras precauciones ya se han descrito antes, recuerda: no utilices el usuario administrador, crea un usuario con permisos muy restringidos y con una buena clave alfanumérica, y si es posible, que no tenga permisos de borrado. Al margen de todo esto, hay que diseñar la aplicación de forma que no se le puedan hacer preguntas maliciosas al servidor. Dependiendo del lenguaje de desarrollo utilizado y de la base de datos, la sintaxis de las técnicas de ataque serán diferentes, pero basadas en los mismos principios. A continuación veremos algunas formas de atacar a un servidor SQL Server con una aplicación desarrollada en ASP.

Como ya sabes, en las aplicaciones ASP, cuando se produce un error de ejecución el sistema responde con una explicación de dónde está el problema, y esto es lo que puede utilizar el atacante para obtener información que le permita llegar a donde quiere. Imaginemos una aplicación que contiene un módulo de identificación hecho con muy poco cuidado. Por ejemplo:



<%@ LANGUAGE="VBScript" %>
<HTML>
<HEAD><TITLE>Pruebas de Seguridad</TITLE></HEAD>
<BODY>
<%
SQL="SELECT clave FROM users WHERE clave = " & Request.QueryString("clave")

	Set DB = Server.CreateObject("ADODB.Connection")
        DB.Open "mi_DB", "mi_user", "mi_clave"

	Set RS = Server.CreateObject("ADODB.Recordset") 
	RS.Open SQL, DB
 
 If RS.BOF And RS.EOF then
    Response.Write("Clave incorrecta")
 Else
        Response.Write("Clave correcta")
 End if

   RS.Close
   DB.Close
   Set RS = Nothing
   Set DB = Nothing
%>
</BODY>
</HTML>

Para obtener acceso simplemente escribimos en la ventana de URL del navegador:
http://mi_servidor/seguridad.asp?clave='prueba1'

La aplicación nos devuelve: Clave incorrecta

Parece que todo funciona bien, pero el atacante cambia de estrategia, y escribe:
http://mi_servidor/seguridad.asp?clave=0

Y la aplicación, indiscreta donde las haya, dice:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Error de sintaxis al convertir el valor varchar 'hola ' para una columna de tipo de datos int.
/seguridad.asp, línea 13

Si... acabamos de darle al pirata las llaves del reino, porque la clave buscada es hola. ¿Qué ha pasado? Pues que nuestra aplicación carece de las más elementales normas de seguridad, y simplemente entrando un tipo de dato diferente del que espera la consulta, lo ha puesto en evidencia.

El primer error de seguridad está en el modo de recibir la consulta: utilizando el objeto Request y su colección QueryString. Esta forma de operar es como abrirle una consola al atacante para que escriba lo que quiera, sin limitar la longitud de su código. La colección Form le dificultaría algo más las cosas, sobre todo si los campos están limitados en longitud, pero también podría conseguir algo. En este caso concreto eso no arreglaría nada, ya que solamente ha tenido que escribir un cero. Lo que sí podría hacer más fiable el programa es filtrar previamente todos los datos que reciba, y solamente después, pasarlos a la consulta SQL, y además, escribir la consulta de otra forma.

Esto no habría ocurrido si, simplemente, escribimos la consulta así:


SQL="SELECT clave FROM users WHERE clave = " &  "'" & Request.QueryString("clave") & "'" 
Quede claro que esto es un error de programación, achacable únicamente al programador, y no es un fallo de diseño de la base de datos ni del servidor web. Este tipo de ataques lo pueden sufrir por igual todas las plataformas de desarrollo: ASP, PHP, .NET, etc., y cualquier base de datos: SQL Server, ORACLE o MySQL.

El ejemplo que hemos visto es muy sencillo, y su fallo clamoroso, pero pueden realizarse ataques más sofisticados mediante una técnica denominada "inyección SQL". Esto consiste en escribir en los formularios, en lugar de los datos solicitados, parte de instrucciones SQL que se concatenarán con la instrucción básica de la aplicación, y la consulta resultante será la que se ejecute, produciendo errores intencionados que, directamente o en varios pasos, pueden ir filtrando la información que el atacante necesita para acceder al servidor.

Modificaremos un poco el ejemplo anterior, y lo haremos con dos ficheros; Uno en html que será el formulario llamador:



<HTML>
<HEAD><TITLE>Pruebas de Seguridad</TITLE></HEAD>
<BODY>

<FORM ACTION="seguridad.asp" METHOD="POST"> 
Usuario: <INPUT TYPE="text" NAME="usuario" SIZE="15" maxlength="15">
Clave: <INPUT TYPE="text" NAME="clave" SIZE="15" maxlength="15">
<INPUT TYPE="submit" NAME="enviar" VALUE="enviar"> 
</FORM> 

</BODY>
</HTML>

Y el mismo ejemplo en ASP anterior, pero con la consulta SQL diferente:



<%@ LANGUAGE="VBScript" %>
<HTML>
<HEAD><TITLE>Pruebas de Seguridad</TITLE></HEAD>
<BODY>
<%
SQL="SELECT clave FROM usuarios WHERE usuario = '" & Request.Form("usuario") & _
     "' And clave = '" &  Request.Form("clave") & "'"

	Set DB = Server.CreateObject("ADODB.Connection")
        DB.Open "mi_DB", "mi_user", "mi_clave"

	Set RS = Server.CreateObject("ADODB.Recordset") 
	RS.Open SQL, DB
 
 If RS.BOF And RS.EOF then
    Response.Write("Clave incorrecta")
 Else
        Response.Write("Clave correcta")
 End if

   RS.Close
   DB.Close
   Set RS = Nothing
   Set DB = Nothing
%>
</BODY>
</HTML>

Como puedes ver, ahora sí se han incluido las comillas que indican que los campos son alfanuméricos, para evitar el desastre provocado por el cero del ejemplo anterior; pero nuestro hacker sabe lo que hace, y escribe en el formulario:

Usuario: Clave:

Y la aplicación devuelve: Clave correcta

Desde luego, ni el usuario ni la clave son correctos, pero la aplicación dice que sí, es decir, que de nuevo se nos han colado en casa sin tener la llave. Y puede que te estés preguntando ... pero, ¿qué ha fallado ahora?. La respuesta, una vez más, está en un error de diseño de la consulta SQL. En efecto, tal como está escrita, y utilizada "honradamente", la consulta después de recibir los valores legales del formulario quedaría así:

SELECT clave FROM usuarios WHERE usuario = 'mi_user' And clave = 'hola'

En lenguaje humano, nuestro deseo es que la DB busque un registro cuyo usuario sea "mi_user" y que su clave, al mismo tiempo, sea "hola". Pero después de recibir los valores escritos por el pirata, queda así:

SELECT clave FROM usuarios WHERE usuario = 'prueba' And clave = '' or 1=1 --'

Y su significado para la máquina es que busque los registros cuyo usuario sea "prueba" y su clave "" (vacia) O que se cumpla la condición (no necesariamente en la tabla) de que 1 sea igual a 1, es decir, todos los registros de la tabla, puesto que esa igualdad se cumple siempre. El diseño de la aplicación solamente evalúa si la consulta devuelve al menos una línea válida, pero en la práctica está devolviendo todas las líneas de la tabla, lo que significa que el atacante podría hacerse con todos nuestros usuarios y sus claves de un solo golpe. ¡Qué peligrosos son los operadores booleanos! porque, como ya habrás supuesto, este nuevo fiasco se debe al operador booleano Or que nos han inyectado en nuestra consulta. El final de la inyección son los dos guiones -- que son el símbolo del comentario para SQL Server, y que evitan que se produzca un error de sintaxis al resultar un número impar de comillas en la consulta.

Esto no habría ocurrido si, simplemente, escribimos la consulta así:


SQL="SELECT clave FROM usuarios WHERE (usuario = '" & Request.Form("usuario") & _
     "') And (clave = '" &  Request.Form("clave") & "')"
Y la aplicación en lugar de mostrar nuestras claves, hubiera contestado.

Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Línea 1: sintaxis incorrecta cerca de '1'.
/seguridad.asp, línea 15

Los ejemplos pueden ser interminables. Dependiendo de cómo esté escrita la consulta y con un poco de paciencia (y los hackers tienen mucha...), se puede terminar abriendo la puerta de los datos. Y te preguntarás ¿qué hacer? Pues ante todo aprender lo más posible del lenguaje SQL de tu servidor, dedicarle un cierto tiempo a probar a romper tu propio programa (si las pruebas las hace otro programador, mejor), y finalmente escribir siempre funciones para controlar el tipo de dato recibido, es decir, que si se espera un número, asegurarse de que en efecto, llega un número, etc., y funciones de bloqueo de ciertos caracteres como las comillas simples ('), las comillas dobles ("), los guiones (--), y todo aquel que pueda dar conflictos en una consulta de tu DB.

Es buena idea programar los módulos de identificación de forma que tengan un límite de intentos, y si éste se supera, que la aplicación se cierre de forma permanente, incluso aunque se entre la clave correcta, obligando a cerrar la sesión y comenzar de nuevo (pero sin informar de ello, claro). Otra buena medida es guardar el IP de las máquinas cliente, y rehusar la conexión de aquellas que hayan sobrepasado el número máximo de intentos hasta que el administrador lo permita. Esto, además, nos permitirá saber después qué máquinas nos están atacando, y si es conveniente, establecer una "lista negra" de IPs o de dominios "non gratos".

Otra cosa a tener en cuenta, es limitar siempre la longitud máxima de los campos de los formularios a la longitud que tenga el campo de destino en la tabla, ni uno más, y que la aplicación rechace los que no sean de la longitud correcta, aunque en realidad las claves deberán ser más cortas que ese máximo. Se trata de evitar que puedan escribir mucho, pero sin indicar claramente la longitud máxima de la clave. Elimina en las pantallas para el usuario esas indicaciones de longitud típicas: ..."Escriba una contraseña (mínimo 5 y máximo 10 caracteres..". Por último, y si tu servidor lo permite, es recomendable configurarlo para que no devuelva explicaciones de los errores, sino un mensaje fijo informando de que se ha producido un error, sin más, ya que los detalles a un usuario normal no le sirven de nada. Activa los mensajes explícitos solamente mientras desarrollas o arreglas algo. De todas formas, recuerda que esto no evitará que, si la inyección se consigue y es correcta, los datos aparezcan, ya que, aunque obtenidos fraudulentamente, no constituyen un error.

Además de ataques más o menos sofisticados, como los descritos, te pueden intentar aplicar los más típicos, como el diccionario o la fuerza bruta. El ataque por diccionario consiste en intentar averiguar la clave de acceso probando una lista de palabras de las más habituales. Esa lista puede ser estándar o personalizada al servidor que se quiera atacar, si se conoce ya algo de él. Si ya se conoce por lo menos un usuario, la lista suele ser con datos personales de ese usuario, como su fecha de nacimiento, el nombre de su hijo, el del perro, la matrícula de su coche, su número de teléfono, etc. etc. Por eso es importante que las claves nunca sean palabras coherentes y mucho menos relacionadas con datos nuestros. Una clave fiable debe ser algo que no signifique nada: por ejemplo: "ocmo12ert24A". ¿Que es muy difícil de recordar? Sí... pero precisamente por eso es buena. Al principio te puede parecer imposible, pero al final te la aprenderás. Lo que ciertamente te va a costar más es que tus usuarios utilicen estas claves, sobre todo si tienen libertad para ponerla ellos mismos. No lo harán.

Otra típica forma de ataque es la de fuerza bruta, es decir, ir probando letras y números de forma aleatoria, o con un cierto orden, hasta que se consiga el acceso. Por supuesto, este sistema puede llevar mucho tiempo, dependiendo de lo buenas que sean las claves utilizadas. Como ya te puedes imaginar, estos ataques no se hacen tecleando a mano posibles claves, sino mediante programas que pueden hacer miles de pruebas en poco tiempo. Por eso, como ya se ha dicho antes, conviene que los módulos de conexión de las aplicaciones tengan un límite de accesos fallidos, a partir del cual, el acceso debe cerrarse a ese cliente, indefinidamente, o por un tiempo prudencial.

Una forma disuasoria para estos ataques es utilizar en los formularios de acceso la técnica "CAPTCHA" (Completely Automated Public Turing test to tell Computers and Humans Apart, que significa algo así como -Prueba de Turing pública y automática para diferenciar máquinas y humanos-) que consiste en obligar a escribir manualmente en el formulario una clave aleatoria distorsionada ópticamente para que no pueda ser leída por un programa. Por ejemplo:


Y aquí tienes un sencillo ejemplo de código CAPTCHA escrito en ASP por Emir Tüzül bajo Common Public License:
Código del llamador   Código generador
Suerte.

[Indice]