Bases de datos, passwords, seguridad y otras yerbas

Hoy por la madrugada paso algo bastante fuerte: hackearon geelbe.com

Para los que no lo saben geelbe es un “club privado de compras”, un modelo distinto a sitios como Mercado Libre o De Remate donde cualquiera puede participar. La idea es lograr tener una red de confianza entre la gente que participa ya que solamente se entra por invitación.

Al margen de como funciona el sitio, esta madrugada se publico en Internet una lista de usuarios con su respectivo password. ¿Como es esto posible? Facil, los passwords estaban guardados en la base de datos en texto plano.

Existen varias formas en las que uno puede elegir guardar el password de sus usuarios en la base de datos, a saber: en texto plano, encriptadas, encriptadas con salt. Cada una tiene sus pro y sus contras, y de hecho dependiendo del tipo de aplicación que estemos desarrollando existen leyes al respecto.

Texto plano

Guardar las claves en texto plano es lo mas simple. Uno tiene registro del password de cada usuario y cuando este intenta ingresar al sistema se compara el password que nos provee contra el que tenemos en la base de datos, si es igual, lo dejamos pasar, si no es igual, impedimos que acceda.

Encriptada

Cuando uno encripta passwords utiliza algún tipo de hash, esto es, un algoritmo que da por resultado una cadena de texto que no se puede revertir al dato que se ingreso originalmente (el password).

Ejemplos de estos algoritmos son md5 y sha1, los mas utilizados en las aplicaciones WEB por cierto.

Encriptada con salt

Para entender la encriptacion con salt primero hay que ver una gran falencia en la encriptacion a secas: Si uno asume que su aplicación puede, por alguna falla de seguridad, llegar a dejar expuesta la base de datos, y por consiguiente tener acceso a los passwords encriptados, estos pueden llegar a ser revertidos.

¿Pero como? Si recién dije que se utilizan algoritmos por los cuales no se puede llegar al password partiendo del resultado del algoritmo, bien, existen lo que se conoce como rainbow tables, que son listas de los passwords ya encriptados y su correspondiente password en texto plano. De esta forma cuando uno tiene un password encriptado, puede ir a una rainbow table pre generada con millones de passwords y ver si lo encuentra ahí, de ser así, tiene la versión en texto plano del mismo. Obviamente también existe la “fuerza bruta”, esto es, teniendo el hash empezar a probar encriptar todas las combinaciones de letras, números, etc hasta llegar a algún hash que coincida, y ahí obtenemos el password original (o también se puede utilizar una lista de los passwords mas comunes para probar).

¿Como evitamos que alguien venga y compruebe los passwords guardados en la base de datos contra una rainbow table y obtenga el password original? Bueno, podemos, en lugar de guardar el hash del password, agregarle una pequeña cadena de texto “random” al password original, y después guardarnos el hash resultante de encriptar eso y también guardarnos la cadena. Esta es la practica mas extendida hoy en día y frameworks como Django ya lo hacen desde el vamos, también el cookbook de Ruby on Rails nos recomienda hacerlo. Es mucho menos probable que existan rainbow con el password mas una cadena al azar de que si existen rainbow tables con el password solamente.

Viendo estas tres opciones tenemos que decir que el caso de Geelbe coincida con el primero, ellos no encriptan los passwords guardados en la base de datos lo cual no seria problema si nadie pudiera acceder a la base de datos.

Puedo asumir que como quien tuvo acceso a los passwords los publico en la web, que no accedio al servidor, ya que su intencion era la de hacer algun daño a la imagen de Geelbe y de haber tenido acceso al servidor seguramente hubiera defaceado (ie: cambiado la pagina por algo tipo “hackeado por pepito”) y no solamente publicado los passwords. Seguramente el acceso se dio por algún SQL Injection como el que Patricio descubrió hace unas semanas en Infobae.

Otro detalle a tener en cuenta, y esta practica no esta tan extendida, es la elección del algoritmo para encriptar/hashear los passwords. Si bien las practicas comunes nos dicen que usemos md5 y sha1, lo cierto es que esos algoritmos no fueron diseñados para esa tarea, son efectivos, si, pero tienen un problema: son rápidos.

¿Que tiene de malo que sean rápidos? Cuando uno controla a un usuario que accede a su sitio por lo general guarda una cookie que. Esta cookie guarda solamente un identificador de sesión el cual en el servidor terminamos asociando con el usuario, esto quiere decir que solamente la primer ves que accede el usuario al sitio se comprueba su password. Así que no necesitamos que sea rápido. ¿Donde si es útil la velocidad del algoritmo de hasheo? Cuando uno trata de hacer brute force. Si vos tenes un hash y queres ir probando todas las palabras posibles contra ese hash, y cada intento te toma milésimas de segundo, vas a llegar mucho mas rápido a destino que si te toma 1 segundo cada intento. Es por eso que es recomendable utilizar algún algoritmo como bcrypt que si están diseñados para guardar passwords de usuarios (¡Es lento apropósito!).

Si la aplicación por otro lado tiene que manejar datos como tarjetas de crédito y cobros (PayPal, Google checkout, etc), recomiendo leer las guiás de PCI y los blogs de la gente que desarrolla los estándares de seguridad para ese tipo de aplicaciones (por suerte hasta ahora no me toco desarrollar ninguna así de critica).

Una nota al margen del objetivo del post (concientizar del sano storage de passwords): La gente de Geelbe esta haciendo un laburo groso, un SQL Injection no es un bug tan raro y el error grave que tuvieron (tener los passwords en pseudo texto plano) es corregible 100%, no seamos botones y pasemos la lista de usuarios afectados y sus passwords por ahí.