Een wachtwoordreset is een login die het wachtwoord overslaat. Elke beveiligingsmaatregel op het loginformulier moet dus ook in de resetflow terugkomen of bewust door iets anders worden vervangen. Is het resetpad zwakker dan het loginpad, dan zal een aanvaller dat pad gebruiken. De OWASP Forgot Password Cheat Sheet noemt deze functie "een veelvoorkomende bron van kwetsbaarheden", met user enumeration als bekendste voorbeeld.
Waarom de resetflow de zwakke schakel is
Een geslaagde login levert een sessie op. Volgens de OWASP-richtlijnen voor sessiebeheer staat een geauthenticeerde sessie-ID tijdelijk gelijk aan de sterkste authenticatiemethode die de applicatie heeft gebruikt. Een reset die eindigt in een sessie, of in een wachtwoord dat de aanvaller zelf heeft gekozen, levert hetzelfde op.
NIST SP 800-63B-4 eist bij AAL2 bewijs van bezit en controle over twee verschillende authenticatiefactoren. Vraagt de login om twee factoren, dan is een reset met één gemaild token een single-factor omweg. Het fragment waarop wij ons baseren behandelt recovery niet; het volledige document bevat wel een sectie over authenticator event management.
Onze eigen regel: vraag bij een account met een ingestelde tweede factor om die factor of om een bewaarde recovery code voordat het nieuwe wachtwoord wordt geaccepteerd, en laat een reset nooit de factor verwijderen of vervangen.
De aanvraagstap
Geef hetzelfde antwoord, ongeacht of het account bestaat. "Als dit adres geregistreerd is, hebben we een e-mail verstuurd" volstaat.
Ook timing lekt informatie. Een handler die bij onbekende adressen vroegtijdig stopt en bij bekende adressen een e-mail verstuurt, verraadt het verschil, wat de melding ook zegt. Voer voor elk verzoek dezelfde logica uit, of geef het versturen van de e-mail over aan een asynchrone job.
Voeg rate limiting per account toe, een CAPTCHA of een vergelijkbare maatregel. Zonder zo'n maatregel kan een aanvaller duizenden resetverzoeken per uur op één account afvuren en de inbox of sms van het slachtoffer volspammen. Vergrendel of wijzig het account niet op basis van een verzoek.
Het token
OWASP stelt vier eisen aan een token of code:
- het wordt gegenereerd met een cryptografisch veilig random-algoritme;
- het is lang genoeg om brute force te weerstaan;
- het wordt veilig opgeslagen;
- het is eenmalig bruikbaar en verloopt na een passende periode.
De cheat sheet noemt geen cijfers voor lengte of levensduur. Het dichtstbijzijnde getal in de bronnen staat in de sessierichtlijnen: een CSPRNG met minimaal 128 bits entropie, bij voorkeur 160 bits of meer. Die richtlijn is geschreven voor sessietokens; wij passen haar toe op resettokens. Kies voor de levensduur een korte waarde, leg die vast en test ertegen.
"Veilig opgeslagen" kunt u strikt uitleggen. Valt alleen-lezen openbaarmaking van de tokenopslag binnen uw dreigingsmodel, dan beschrijven de sessierichtlijnen een opsplitsing in identifier en geheime verifier. De server bewaart de publieke lookup-identifier en de volledige SHA-256-hash van de verifier, en vergelijkt hashes in constante tijd. De identifier alleen mag nooit als bewijs gelden. Deze toepassing op resettokens is onze eigen suggestie.
Lever het token af via een apart kanaal, e-mail of sms, en nooit in de response aan de browser. Een token in de URL is het eenvoudigste ontwerp, maar de sessierichtlijnen waarschuwen dat ID's in URL's kunnen lekken via links en logbestanden, browsergeschiedenis en bladwijzers, de Referer header en zoekmachines. Als u op de resetpagina geen content van derden en geen uitgaande links toelaat, dicht u alleen het Referer-lek. Voor de rest wisselt u bij het eerste verzoek het token in voor kortlevende state aan de serverkant, stuurt u door naar een schone URL en houdt u die eerste query string buiten de access logs.
De resetstap
- Laat de gebruiker het nieuwe wachtwoord tweemaal invoeren en toets het aan hetzelfde beleid als bij registratie.
- Hash het via hetzelfde codepad als elk ander wachtwoord.
- Maak alle openstaande resettokens van het account ongeldig zodra het wachtwoord of het e-mailadres verandert. Anders kan een oudere e-mail die nog in een inbox staat het account opnieuw resetten.
- Stuur de gebruiker een e-mail dat het wachtwoord is gewijzigd. Zet het wachtwoord nooit in het bericht.
- Stuur de gebruiker door naar de normale login in plaats van hem automatisch in te loggen. Automatisch inloggen voegt code voor sessiebeheer toe, en daarmee de kans op nieuwe kwetsbaarheden.
- Beëindig bestaande sessies, of bied dat in elk geval aan.
Na een vermoedelijke compromittering overleeft de live sessie van de aanvaller een wachtwoordwijziging, tenzij u die beëindigt. Wij zouden beëindiging de standaard maken.
MFA en gecompromitteerde accounts
Een wachtwoordreset alleen herstelt de controle mogelijk niet. De aanvaller kan nog een actieve sessie hebben, of recovery-gegevens of MFA-methoden hebben gewijzigd.
OWASP zegt dat u niet uitsluitend moet vertrouwen op recent toegevoegde of gewijzigde recovery-gegevens. Gebruik onafhankelijk bewijs dat eerder is vastgelegd, zoals bewaarde recovery codes, in een combinatie die aan de assurance-eisen van het account voldoet. Het resetten van MFA heeft een eigen sectie in de Multifactor Authentication Cheat Sheet van OWASP, dus houd dat proces gescheiden van de wachtwoordflow.
De OWASP Authentication Cheat Sheet behandelt ook het wijzigen van een geregistreerd e-mailadres. Dat is van belang, omdat een gewijzigd adres elke toekomstige reset omleidt.
De flow testen
| Test | Zo ziet een geslaagde test eruit |
|---|---|
| Bestaand en niet-bestaand adres | Zelfde melding en statuscode |
| Gescripte reeks verzoeken per adres | Mediane responstijden komen overeen |
| Herhaalde verzoeken voor één account | Rate limit of CAPTCHA grijpt in |
| Een reset aanvragen en daarna inloggen | Account niet vergrendeld of gewijzigd |
| Token twee keer gebruikt, of na verlopen | Poging mislukt |
| Oud token na wijziging van wachtwoord of e-mailadres | Poging mislukt |
| Resetpagina met het token in de URL | Geen verzoeken aan derden of uitgaande links |
| Reset met een oude sessie nog open | Oude sessie beëindigd |
| Ingestelde tweede factor, alleen gemaild token (onze regel) | Reset geweigerd |
| Eindresponse en de e-mail | Geen automatische login, geen wachtwoord in de e-mail |
Vergelijk bij de timingtest de medianen en de spreiding over veel runs. Dit hoort bij elke penetratietest van een authenticatieflow.
Waar u kunt beginnen
- Vraag voor een bestaand en een niet-bestaand account elk vele malen een reset aan. Vergelijk melding, statuscode en responstijd.
- Lees de tokengenerator na. Controleer dat die een CSPRNG gebruikt, maak tokens eenmalig bruikbaar en stel een levensduur in die u in minuten kunt noemen.
- Voeg rate limiting per account of een CAPTCHA toe aan het aanvraag-endpoint en controleer dat een verzoek het account nooit vergrendelt of wijzigt.
- Laat de reset andere sessies beëindigen, openstaande tokens ongeldig maken en een notificatie-e-mail zonder wachtwoord versturen. Controleer dat de resetpagina niets van derden laadt.
- Neem een testaccount met MFA en probeer het te resetten met alleen het gemailde token. Controleer dat de reset wordt geweigerd.
- Controleer wie een tweede factor kan resetten of verwijderen, welk bewijs diegene moet overleggen en of recovery recent gewijzigde gegevens als onbetrouwbaar behandelt.
