4dim / Notas

Recuperar la contraseña sin delatar quién trabaja dónde

El formulario de «olvidé mi contraseña» es una lista de clientes si responde distinto según exista la cuenta, o si tarda distinto. La misma respuesta y el mismo tiempo, enlaces que se matan entre sí, dos caminos con un mecanismo, y el correo feo a propósito.

El formulario que es una lista de clientes

Si tu equipo entra a un sistema con correo y contraseña, esta nota va de la pantalla de «Olvidé mi contraseña». Parece el formulario más inofensivo de una aplicación. Es el más indiscreto.

Si al escribir un correo la pantalla responde «ese correo no está registrado», acaba de confirmar quién no es cliente. Si responde «te mandamos un enlace», acaba de confirmar quién sí. Con una lista de correos y paciencia, ese formulario le cuenta a cualquiera qué personas trabajan en qué negocios.

Para un CRM donde conviven muchos negocios, eso no es un detalle de cortesía. Es la diferencia entre proteger la lista de clientes y publicarla de a uno.

La misma respuesta, y el mismo tiempo

La primera medida es obvia: la pantalla contesta siempre lo mismo, exista o no la cuenta. «Si el correo está registrado, te llegará un enlace».

La segunda es la que casi nadie toma: el tiempo también responde. Si el servidor espera a que el correo salga antes de contestar, la respuesta tarda medio segundo más cuando la cuenta existe. Con un cronómetro, el formulario sigue delatando.

Por eso la función que atiende el formulario genera el enlace y devuelve el control de inmediato. El envío del correo se dispara aparte, y la respuesta no lo espera. Exista o no la cuenta, el navegador recibe lo mismo en el mismo tiempo.

Un mensaje idéntico no basta si una respuesta tarda más que la otra. La respuesta es lo que dice y lo que tarda.

Enlaces que se matan entre sí

Emitir un enlace nuevo invalida cualquier enlace anterior sin usar de esa cuenta. Las dos cosas ocurren en la misma operación de la base: o pasan juntas o no pasa ninguna. Sin eso, cada solicitud deja un enlace válido más, y quien recibió el de ayer sigue teniendo la llave de una puerta que ya se creía cerrada. Un correo comprometido meses después seguiría sirviendo.

Y si ya hay un enlace vivo de hace menos de cinco minutos, no se emite otro ni se reenvía el correo. Pulsar el botón cinco veces tiene que mandar un correo, no cinco. Eso protege al usuario impaciente y protege la reputación del dominio de correo, que es lo que se pierde cuando alguien usa el formulario para hacer spam.

Dos caminos, un mecanismo

Hay dos formas de recuperar el acceso y las dos usan el mismo enlace de un solo uso. Lleva 32 bytes de azar, o sea un código tan largo que no se acierta probando, y está pensado para pegarse, no para teclearse. Lo que cambia es quién ve el enlace.

  • El dueño del negocio puede emitir un enlace de rescate para alguien de su equipo. Él sí lo ve en pantalla, y lo reenvía por el canal que quiera. Se confía en él porque es el dueño.
  • El autoservicio nunca enseña el enlace: lo manda al correo escrito, a ciegas. Solo quien controla ese buzón puede completarlo. La persona que lo pidió no ve nada, y por eso no puede filtrar nada.

Es el mismo diseño de las invitaciones. Se guarda la intención, que es el correo y el rol, se manda un enlace, y la persona pone su propia contraseña. Antes, el dueño tecleaba la contraseña de la otra persona y «durante un tiempo sabía su clave». Ya no. Nadie debe conocer la contraseña de otro, ni un minuto.

Al completar el restablecimiento se abre sesión en el mismo paso. La identidad acaba de probarse gastando un enlace de un solo uso. Mandar a la persona al formulario de entrar, a teclear lo que escribió hace un segundo, es un paso que no comprueba nada y donde se pierde gente.

El correo feo a propósito

El correo de recuperación va en texto plano, corto, sin logo y sin botón de colores. Un correo de seguridad con plantilla bonita tiene la forma exacta del phishing, esos correos falsos que imitan a una empresa para robar contraseñas. El nuestro dice quién lo manda, qué hacer y cuánto dura el enlace. Nada más.

Y el mensaje de «enlace inválido» no distingue entre cuatro causas: no existe, ya se usó, se canceló o caducó. A quien llega con un enlace muerto le da igual el motivo. Y distinguirlos le diría a un extraño si ese enlace existió alguna vez.

Lo que hay alrededor

  • La sesión es un código opaco guardado en la base, más una firma en la cookie del navegador. Opaco quiere decir que el código no dice nada por sí mismo. Sin la firma, alguien que solo pudiera leer la tabla de sesiones fabricaría cookies válidas. Sin el código en la base, no habría forma de cortar una sesión activa. Hacen falta las dos. Dura 8 horas.
  • El límite de intentos de acceso es de 8 fallos en 15 minutos, por correo o por IP, la dirección desde la que se conecta un equipo. Basta con pasarse en uno de los dos. Así se cubren los dos ataques: muchos intentos contra una cuenta desde muchas direcciones, y muchos intentos contra muchas cuentas desde una sola.
  • El alta pública se limita solo por IP: 3 altas o 12 intentos por hora. Nunca por correo, porque «el correo lo elige el que abusa». El criterio de un límite es el dato que el atacante no controla.

Qué hacer entonces

  • Misma respuesta y mismo tiempo, exista o no la cuenta. Mandar el correo fuera del camino de la respuesta.
  • Un enlace nuevo mata los anteriores. Y no más de uno cada pocos minutos.
  • Que nadie vea nunca la contraseña de otro, ni el enlace de otro si no es el dueño.
  • Correo de seguridad en texto plano.
  • Mensajes de error que no confirman la existencia de nada.
  • Límites por el dato que el atacante no elige: correo o IP al entrar, IP al registrarse.

Esta nota sale de nuestro trabajo en Software a medida.

← todas las notas