Correos para restablecer la contraseña: fiables y en la bandeja de entrada

Crea un flujo seguro para restablecer contraseñas: tokens de un solo uso, caducidad corta, sin enumeración de cuentas, una plantilla clara y confirmación.

El correo de restablecimiento de contraseña es la llave maestra de tu producto. Cualquiera que pueda leerlo puede hacerse con la cuenta; por eso los atacantes lo tienen en el punto de mira y por eso los usuarios han aprendido a desconfiar de él.

Un buen flujo de restablecimiento tiene que ser lo bastante seguro para resistir a esos atacantes y lo bastante claro para que los usuarios reales confíen en él en pocos segundos. Esta guía recorre ambos aspectos, desde el momento en que alguien hace clic en «¿Has olvidado tu contraseña?» hasta el correo de confirmación después del cambio.

El flujo de un vistazo

  1. El usuario introduce su correo en la página ¿Has olvidado tu contraseña?.
  2. Tu app muestra siempre el mismo mensaje, exista o no la cuenta.
  3. Si existe, creas un token de un solo uso y envías por correo un enlace de restablecimiento.
  4. El usuario abre el enlace, elige una contraseña nueva y el token queda consumido.
  5. Cierras las demás sesiones del usuario y envías un correo de «tu contraseña ha cambiado».

Paso 1: No reveles quién tiene cuenta

Después de enviar el formulario, responde siempre con el mismo texto:

Si existe una cuenta para ada@example.com, te hemos enviado un enlace para restablecer tu contraseña. Caduca en 30 minutos.

Mostrar en su lugar «No hay ninguna cuenta con ese correo» le dice a cualquiera con una lista de direcciones exactamente cuáles usan tu producto. Mantén también un tiempo de respuesta similar: haz la búsqueda de la cuenta y el envío del correo en segundo plano para que la página no responda notablemente más rápido con las direcciones desconocidas.

Paso 2: Crea un token robusto de un solo uso

El token del enlace debe ser largo, aleatorio e imposible de adivinar:

import { randomBytes, createHash } from 'node:crypto';

const token = randomBytes(32).toString('base64url');            // goes in the email
const tokenHash = createHash('sha256').update(token).digest('hex'); // goes in the database

await db.passwordResets.upsert({
  userId: user.id,
  tokenHash,
  expiresAt: new Date(Date.now() + 30 * 60 * 1000), // 30 minutes
});

Las reglas:

  • Guarda solo un hash del token, para que una filtración de la base de datos no reparta enlaces de restablecimiento válidos.
  • Un token activo por usuario. Emitir uno nuevo sustituye al anterior.
  • Caducidad corta: lo habitual es entre 15 y 60 minutos.
  • Un solo uso. Elimina el token en cuanto se cambie la contraseña.
  • Invalídalo si, mientras tanto, el usuario inicia sesión correctamente o cambia su dirección de correo.

Paso 3: Envía el correo de inmediato

El usuario está esperando, así que envíalo dentro de la solicitud, no en un proceso por lotes:

import os
import requests

def send_reset_email(user, token):
    link = f"https://app.yourco.com/reset-password/{token}"
    res = requests.post(
        "https://backend.inbixio.com/api/send-email/",
        headers={"X-API-Key": os.environ["INBIXIO_API_KEY"]},
        json={
            "to_email": user.email,
            "subject": "Reset your YourApp password",
            "message": render_reset_template(name=user.first_name, link=link, minutes=30),
        },
        timeout=10,
    )
    res.raise_for_status()

Envíalo desde una dirección dedicada y autenticada, como security@yourco.com. En Inbixio, conecta ese buzón como su propio servidor de correo y dale al servicio de autenticación una clave de API fijada a él, para que los correos de restablecimiento lleguen desde la dirección que los usuarios esperan. Si alguna vez eliminas ese servidor, vuelve a fijar la clave. Consulta la seguridad de las claves de API para configurarlo.

Paso 4: Escribe un correo de restablecimiento que inspire confianza

Los correos de phishing imitan los restablecimientos de contraseña más que cualquier otro mensaje. Haz que el tuyo sea inconfundible:

  • Asunto: sencillo y concreto, p. ej. «Restablece tu contraseña de YourApp». Sin urgencia ni signos de exclamación.
  • Un botón claro, más el enlace completo como texto para los clientes que bloquean los botones.
  • La caducidad: «Este enlace caduca en 30 minutos».
  • El contexto: cuándo se hizo la solicitud y, si lo sabes, desde qué navegador o ciudad.
  • Qué hacer si no fue el usuario: «Si no has pedido restablecer tu contraseña, puedes ignorar este correo. Tu contraseña no cambiará».
  • Ningún otro enlace, imagen ni promoción. Cuantos menos enlaces, más fácil es verificarlo.
<div style="font-family:system-ui,sans-serif;max-width:520px;margin:auto;color:#111;line-height:1.5">
  <p>Hi Ada,</p>
  <p>We received a request to reset the password for your YourApp account.</p>
  <p style="margin:28px 0">
    <a href="https://app.yourco.com/reset-password/TOKEN"
       style="background:#584efe;color:#fff;padding:12px 20px;border-radius:8px;text-decoration:none;font-weight:600">
      Choose a new password
    </a>
  </p>
  <p>This link expires in 30 minutes and can only be used once.</p>
  <p>If you didn't ask to reset your password, you can safely ignore this email.</p>
  <p style="color:#666;font-size:13px">Button not working? Paste this link into your browser:<br>
    https://app.yourco.com/reset-password/TOKEN</p>
</div>

Paso 5: Gestiona el enlace con cuidado

Cuando el usuario abre el enlace:

  • Busca el hash del token, comprueba que no ha caducado y muestra el formulario de «nueva contraseña». Todavía no inicies la sesión del usuario.
  • Mantén el token fuera de las solicitudes a terceros. Añade <meta name="referrer" content="no-referrer"> a la página de restablecimiento y no cargues en ella scripts de analítica ni de publicidad, para que el token de la URL no se filtre a través de las cabeceras Referer.
  • Al enviar el formulario, comprueba la nueva contraseña con tus reglas de contraseñas, aplícale un hash con un algoritmo lento (bcrypt, scrypt o Argon2), elimina el token y cierra todas las demás sesiones.

Paso 6: Confirma el cambio

Envía siempre una confirmación breve tras un cambio de contraseña:

Tu contraseña de YourApp se cambió el 28 de octubre a las 14:32 UTC. Si fuiste tú, no tienes que hacer nada más. Si no, protege tu cuenta de inmediato.

Este correo es la alarma del usuario si otra persona ha entrado en su cuenta, así que no lo omitas nunca.

Asegúrate de que llega

Un correo de restablecimiento en la carpeta de spam es un ticket de soporte. Antes del lanzamiento:

  • configura SPF, DKIM y DMARC para tu dominio de envío,
  • haz pruebas con direcciones de Gmail y Outlook y comprueba que las cabeceras muestran PASS, y
  • vigila la tasa de Failed Deliveries (entregas fallidas) en tu panel de Inbixio después de desplegar.

Lista de comprobación

  • La misma respuesta para correos existentes y desconocidos
  • Token aleatorio de 32 bytes; solo se guarda su hash
  • Caducidad de 15–60 minutos, un solo uso, un token activo por usuario
  • Envío inmediato desde un remitente dedicado y autenticado
  • Plantilla clara: un botón, el enlace en texto, la caducidad y la línea de «¿no has sido tú?»
  • Sin scripts de terceros en la página de restablecimiento; referrer desactivado
  • Cierre de las demás sesiones y correo de confirmación enviado tras el cambio

Envíalo con Inbixio

Conecta tu propio servidor SMTP, crea una clave de API con permisos limitados y envía desde cualquier lenguaje con una sola solicitud HTTPS.

Crear cuenta Ver precios