E-mail do resetowania hasła: bezpieczny i trafiający do skrzynki

Bezpieczny proces resetowania hasła: jednorazowe tokeny, krótka ważność, brak enumeracji kont, czytelny szablon e-maila i potwierdzenie po zmianie hasła.

E-mail do resetowania hasła to klucz uniwersalny do Twojego produktu. Każdy, kto może go przeczytać, może przejąć konto, dlatego atakujący biorą go na cel, a użytkownicy nauczyli się podchodzić do niego podejrzliwie.

Dobry proces resetowania musi być na tyle bezpieczny, by oprzeć się atakującym, i na tyle czytelny, by prawdziwi użytkownicy zaufali mu w kilka sekund. Ten poradnik omawia oba aspekty, od chwili kliknięcia „Nie pamiętasz hasła?” aż po e-mail z potwierdzeniem zmiany.

Proces w skrócie

  1. Użytkownik wpisuje swój adres e-mail na stronie Nie pamiętasz hasła.
  2. Twoja aplikacja zawsze pokazuje ten sam komunikat, niezależnie od tego, czy konto istnieje.
  3. Jeśli istnieje, tworzysz jednorazowy token i wysyłasz e-mailem link do resetowania.
  4. Użytkownik otwiera link, ustawia nowe hasło, a token zostaje zużyty.
  5. Wylogowujesz pozostałe sesje użytkownika i wysyłasz e-mail „Twoje hasło zostało zmienione”.

Krok 1: Nie zdradzaj, kto ma konto

Po wysłaniu formularza zawsze odpowiadaj tym samym tekstem:

Jeśli istnieje konto dla adresu ada@example.com, wysłaliśmy link do zresetowania hasła. Wygaśnie za 30 minut.

Komunikat „Brak konta z tym adresem e-mail” mówi każdemu, kto ma listę adresów, dokładnie które z nich korzystają z Twojego produktu. Zadbaj też o podobny czas odpowiedzi: wyszukiwanie konta i wysyłkę e-maila wykonuj w tle, aby dla nieznanych adresów strona nie odpowiadała zauważalnie szybciej.

Krok 2: Utwórz silny, jednorazowy token

Token w linku musi być długi, losowy i niemożliwy do odgadnięcia:

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
});

Zasady:

  • Przechowuj tylko skrót tokenu, aby wyciek bazy danych nie rozdawał działających linków resetujących.
  • Jeden aktywny token na użytkownika. Wydanie nowego zastępuje stary.
  • Krótka ważność: typowo od 15 do 60 minut.
  • Jednorazowe użycie. Usuń token, gdy tylko hasło zostanie zmienione.
  • Unieważnij go, jeśli w międzyczasie użytkownik zaloguje się pomyślnie lub zmieni adres e-mail.

Krok 3: Wyślij e-mail natychmiast

Użytkownik czeka, więc wysyłaj w ramach żądania, a nie w zadaniu wsadowym:

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()

Wysyłaj go z osobnego, uwierzytelnionego adresu, np. security@yourco.com. W Inbixio podłącz tę skrzynkę jako osobny serwer pocztowy i daj usłudze uwierzytelniania klucz API przypięty do niego, aby e-maile resetujące przychodziły z adresu, którego użytkownicy się spodziewają. Jeśli kiedykolwiek usuniesz ten serwer, przypnij klucz ponownie. Jak to skonfigurować, przeczytasz w artykule bezpieczeństwo kluczy API.

Krok 4: Napisz e-mail, któremu ludzie ufają

E-maile phishingowe podszywają się pod resety haseł częściej niż pod jakąkolwiek inną wiadomość. Spraw, by Twój był nie do pomylenia:

  • Temat: prosty i konkretny, np. „Zresetuj hasło do YourApp”. Bez presji czasu i wykrzykników.
  • Jeden wyraźny przycisk oraz pełny link jako tekst dla klientów, które blokują przyciski.
  • Czas ważności: „Ten link wygaśnie za 30 minut”.
  • Kontekst: kiedy wysłano prośbę i, jeśli masz te dane, z jakiej przeglądarki lub miasta.
  • Co zrobić, jeśli to nie on: „Jeśli nie prosiłeś o zresetowanie hasła, zignoruj tę wiadomość. Twoje hasło się nie zmieni”.
  • Żadnych innych linków, obrazków ani promocji. Im mniej linków, tym łatwiej zweryfikować wiadomość.
<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>

Gdy użytkownik otwiera link:

  • Wyszukaj skrót tokenu, sprawdź, czy nie wygasł, i pokaż formularz „nowe hasło”. Jeszcze nie loguj użytkownika.
  • Nie przekazuj tokenu w żądaniach do stron trzecich. Dodaj <meta name="referrer" content="no-referrer"> do strony resetowania i nie ładuj na niej skryptów analitycznych ani reklamowych, aby token z adresu URL nie wyciekł przez nagłówki referrer.
  • Po wysłaniu formularza sprawdź nowe hasło pod kątem Twoich zasad dotyczących haseł, zahaszuj je wolnym algorytmem (bcrypt, scrypt lub Argon2), usuń token i wyloguj wszystkie pozostałe sesje.

Krok 6: Potwierdź zmianę

Po zmianie hasła zawsze wysyłaj krótkie potwierdzenie:

Hasło do Twojego konta YourApp zostało zmienione 28 października o 14:32 UTC. Jeśli to Ty, nie musisz nic robić. Jeśli nie, natychmiast zabezpiecz swoje konto.

Ten e-mail to dzwonek alarmowy dla użytkownika, jeśli do konta dostał się ktoś inny, więc nigdy go nie pomijaj.

Upewnij się, że dociera

E-mail resetujący w folderze spamu to zgłoszenie do supportu. Przed startem:

  • skonfiguruj SPF, DKIM i DMARC dla domeny nadawczej,
  • przetestuj na adresach Gmail i Outlook i sprawdź, czy nagłówki pokazują PASS,
  • po wdrożeniu obserwuj wskaźnik Failed Deliveries (nieudane dostarczenia) w panelu Inbixio.

Checklista

  • Ta sama odpowiedź dla istniejących i nieznanych adresów
  • 32-bajtowy losowy token, przechowywany tylko jego skrót
  • Ważność 15–60 minut, jednorazowe użycie, jeden aktywny token na użytkownika
  • Wysyłka natychmiastowa z osobnego, uwierzytelnionego adresu nadawcy
  • Czytelny szablon: jeden przycisk, zwykły link, czas ważności, zdanie „to nie Ty?”
  • Brak skryptów stron trzecich na stronie resetowania; referrer wyłączony
  • Pozostałe sesje wylogowane i e-mail z potwierdzeniem wysłany po zmianie

Wyślij to przez Inbixio

Podłącz własny serwer SMTP, utwórz klucz API z ograniczonymi uprawnieniami i wysyłaj z dowolnego języka jednym żądaniem HTTPS.

Załóż konto Zobacz cennik