Hasta ahora un
problema recursivo de Velneo en la web son los
formularios por método post, de no ser que hagas uso intensivo del plugin vPost para su envío.
Los problemas que he ido encontrando a lo largo de los años han sido:
el proxy-caché de Telefónica, los
antivirus que trastean con los paquetes TCP de forma "transparente", y últimamente el navegador
Opera.
Las soluciones hasta ahora eran obvias: que no te mienta tu proveedor de internet y que tu antivirus "transparente" lo sea de verdad, pero para Opera no he encontrado solución sin utilizar
vPost.
Con vPost y Opera aún experimento algunos problemas pero estoy en ello.
Como al parecer era un problema de protocolo me instalé un
analizador de tráfico de red para poder ver los paquetes que viajaban entre el navegador Opera y el vServer. Analizando los paquetes pude ver que el navegador sí envía la información por post al vServer, pero usando el protocolo
http1.1 en lugar del http1.0 que es el que soporta vServer.
El problema
parece estar ahí y
la solución debe ser vPost.
Ya que estaba mirando paquetes, vi que el
formulario (nombre de usuario y contraseña) estaba mandando la
contraseña como texto plano en el paquete, ya que no estaba en una conexión segura
https.
Si necesitamos un entorno seguro lo que debemos hacer es montar un
Apache intermedio haciendo
proxy inverso delante del vServer.
Una buena solución para evitar que las contraseñas se manden en plano es
encriptar la contraseña en el cliente con javascript antes de hacer el envío del formulario. En el servidor comparamos la contraseña encriptada recibida con la guardada en la base de datos y validamos.
Para ello tenemos dos opciones en la base de datos: guardar la contraseña encriptada, o guardarla como texto plano.
Por razones de seguridad; si alguien obtiene acceso indebido al servidor y a las tablas de datos, o entra un ladrón a la oficina y se lleva el disco duro,
deberíamos guardar siempre las contraseñas encriptadas en la base de datos ya que así, aunque obtengan las contraseñas no podrán usarlas por estar encriptadas y
no haber vuelta atrás.
Llegados a este punto mi principal preocupación pasa a ser la posible vuelta atras:
es posible desencriptar las contraseñas?Los algoritmos de encriptación suelen basarse en obtener resúmenes,
hash o
"picadillos" de la cadena original.
Usando algoritmos estandard de encriptación como
md5 o
sha, en teoría no es posible, aunque estos algoritmos presentan un problema: como su dominio es infinito (las posibles cadenas a encriptar) y su resultado sí es finito (cadenas de n bits de longitud) tienen posibles
colisiones.
Una colisión es encontrar dos cadenas que encriptadas tengan el mismo resumen.
Es fácil encontrar una colisión?
En principio no es fácil, pero en los últimos años hay ejemplos publicados de
colisiones md5; dos pdf's diferentes con el mismo md5, o incluso un equipo chino que dice hallar
colisiones sha en tiempos muy inferiores a los estimados en teoría.
Para encontrar colisiones se usan
tablas rainbow que son gigantescas tablas de cadenas originales con su hash, resumidas y vueltas a encriptar, resumidas de nuevo y vueltas a encriptar, etc.
La
búsqueda de hashes de forma recursiva sobre estas tablas permite la obtención de colisiones en tiempos muy inferiores a la fuerza bruta.
Qué ocurre si encontramos colisiones? Que el algoritmo de encriptación queda
debilitado y su uso para fines seguros queda en entredicho.
Ahora, no es lo mismo buscar
dos cadenas cualquiera que tengan el mismo hash, que buscar
otra cadena que tenga el mismo hash que una dada.
Aquí es donde entra a jugar el
cumpleaños.
Cuál es el número mínimo de personas que deben reunirse en una habitación para que la probabilidad de que dos de ellas cumplan años el mismo día sea mayor del 50%?
Si definimos
probabilidad de que suceda algo como el
número de casos favorables dividido por el número de casos posibles, y si definimos como probabilidad del caso contrario como 1 - p, siendo p la probabilidad del caso positivo, preguntémonos
cuál es la probabilidad de que las personas reunidas en una habitación no cumplan años el mismo día.
Para la primera persona la probabilidad sería
365 días posibles entre
365 días disponibles.
Para la segunda persona la probabilidad sería de
365 - 1 días posibles (los 365 del año menos la fecha del cumpleaños de la primera) entre
365 días posibles.
Para la tercera sería 365 - 2 entre 365, etc. Es decir,
p = (365/365) * ((365 - 1)/365) * ((365 - 2)/365)* ... * ((365 - n + 1)/365)o sea,
p = (365!)/((365^n)*((365 - n)!))Así pues, la probabilidad de que dadas
n personas reunidas en una habitación, dos de ellas cumplan años el mismo día es
1 - p, y con
n=22 ya obtenemos una probabilidad del
50,7%Para 30 personas la probabilidad es más del 70%, para 40 casi del 90% y para
60 más del
99%La probabilidad de que
dada una persona en el grupo hallar otra que cumpla años el mismo día es mucho menor,
p = 1 - ((364/365)^n)Necesitaríamos un grupo de
253 personas para que esa probabilidad sea mayor del
50%Así las cosas, para una función criptográfica de 128 bits, para encontrar una cadena que tuviese el mismo hash que otra deberíamos probar
2^128 valores, pero para encontrar dos cadenas cualquiera que diesen el mismo hash sólo deberíamos probar
2^64 valores.
Son
números grandes, pero a día de hoy, con los medios tecnológicos disponibles;
PS3, portátiles más potentes que mi equipo de sobremesa para desarrollo, el cloud-computing, la computación distribuida, redes p2p, no sería descabellado dedicar ciertos esfuerzos a romper esas contraseñas si la información reservada que hay detrás puede suponer mucho, mucho, mucho dinero.
Tras tener todo esto en cuenta decidí que si la información que guardo detrás del formulario de nombre de usuario y contraseña por método post fuese lo suficientemente sensible y crítica, la guardaría en un
entorno seguro https, pero como no es así no voy a hacer nada.
Además, quién va a querer perder el tiempo para obtener esa información y qué le va a aportar?
Nadie y nada.
Un saludo,