Waarom een geldige eenmalige code toch mislukt bij de VPN-login
Een geweigerde code is meestal een probleem met de volgorde van de prompts, de inschrijving of de timing, niet een verkeerde code. Controleer deze punten op volgorde voordat je iets opnieuw inschrijft.
Je opent de VPN-client, typt het wachtwoord, en de zes cijfers van je authenticator komen terug als ongeldig — twee keer, dan een derde keer. Er is sinds gisteren niets aan het account veranderd, dus het instinct is de vermelding in de authenticator te verwijderen en opnieuw te scannen — meestal de verkeerde reparatie. Een eenmalige code is geen tweede wachtwoord: de gateway moet er in een bepaalde stap, uit een bepaalde ingeschreven vermelding, binnen een bepaald venster om vragen, en de meeste afwijzingen gebeuren voordat de cijfers worden vergeleken. Stel vast in welke stap je zit voordat je de inschrijving aanraakt.
De volgorde van de prompts vertelt in welke flow je zit
Drie vormen dekken bijna elke VPN-login met een code. In de tweestapsvorm stuurt de client het wachtwoord, geeft de server een uitdaging af, en vraagt de client opnieuw. In de gecombineerde vorm wil de gateway wachtwoord en code in één inzending — soms aaneengeschakeld, soms na een scheidingsteken dat alleen de operator documenteert. In de browservorm heeft de client helemaal geen veld: de code gaat in een webpagina, of een pushgoedkeuring vervangt hem, en de desktopclient wacht op het resultaat.
De verkeerde vorm ziet eruit als een slechte code. Plak een verse code in een veld dat alleen voor het wachtwoord is, en de server leest hem als deel van het wachtwoord. Aan de clientkant maken OpenVPN 2.4 en later het verschil zichtbaar: een server die antwoordt met AUTH_FAILED,CRV1: verwacht een uitdagingsantwoord, dus het profiel heeft static-challenge nodig of een wachtwoordbestand in SCRV1:-vorm. Een ouder profiel met alleen auth-user-pass verifieert het wachtwoord en blijft dan steken, wat in het log op een OTP-fout lijkt terwijl er geen code is verzonden.
WireGuard verdient een vermelding als de uitzondering: het authenticeert sleutelparen in plaats van mensen, dus er is geen veld voor een code. Als een provider er een adverteert, is het iets buiten de tunnel dat hem accepteert.
Wat de server met de zes cijfers doet
Tijdgebaseerde codes volgen RFC 6238, dat de oudere tellergebaseerde constructie uit RFC 4226 inwikkelt: een HMAC over een bewegende factor, standaard afgekapt tot zes cijfers. Voor TOTP is de bewegende factor de huidige Unix-tijd gedeeld door een stap, 30 seconden tenzij de operator die heeft gewijzigd. De verifier vergelijkt je cijfers nooit met een opgeslagen waarde; hij herberekent de verwachte code uit de gedeelde seed en accepteert meestal ook de naburige stappen, zodat een trage heen-en-terugreis de login niet laat mislukken.
Twee gevolgen worden gemist. De tijdzone van de telefoon is irrelevant, omdat de seed nooit een lokale klok ziet — alleen de afwijking van de echte UTC telt, en een toestel dat twee minuten voorloopt faalt bij elke code terwijl het een schone aftelling toont. En een code is per ontwerp eenmalig: de verifier onthoudt de laatste tellerwaarde die hij voor die seed accepteerde, dus dezelfde cijfers die opnieuw worden ingediend, worden zelfs binnen hetzelfde venster geweigerd. Een client die na een time-out opnieuw probeert, kan de code die hij net verstuurde verbranden.
Tellergebaseerde tokens verschuiven hun teller bij elke druk, dus ze raken uit sync nadat codes zijn gegenereerd maar nooit verzonden; de gebruikelijke reparatie is een hersynchronisatievenster dat een paar waarden vooruit accepteert. Als de operator HOTP heeft ingeschreven en je app toont TOTP, is elke waarde fout op een manier die op een klokprobleem lijkt. De provisioning-URI achter de QR-code noemt het type, de cijfers, de periode en de hash.
Fouten die op een verkeerde code lijken
De ingeschreven vermelding is de meest voorkomende boosdoener. Authenticator-apps labelen vermeldingen op issuer en account, dus wie twee identiteiten op dezelfde VPN heeft, kan twee vermeldingen krijgen waarvan de labels één teken verschillen. Een code is geldig voor de seed die hem genereerde en voor niets anders. Vergelijk het label op de telefoon met de gebruikersnaam die de server vastlegt, niet met wat je denkt te hebben getypt.
Ten tweede een niet-passende parameterset. Een seed die is ingeschreven met acht cijfers, een periode van 60 seconden of SHA-256 levert codes die een verifier die zes cijfers, 30 seconden en SHA-1 verwacht weigert, en bij de client is dat niet te onderscheiden van een verkeerde code. Het verschijnt na migraties waarbij de vermelding opnieuw is toegevoegd vanaf een foto van de QR-code, of waarbij het tokenrecord met standaardwaarden opnieuw is opgebouwd.
Ten derde gaat het niet om de code. Gateways geven meestal één generieke authenticatiefout voor een verkeerd wachtwoord, een verlopen code en een uitgeschakeld account, bewust, zodat niemand kan nagaan welke factor faalde. Lees het gateway- of RADIUS-log in plaats van de banner van de client: een nooit uitgegeven uitdaging, een toegangsweigering zonder OTP-attribuut en een beleidsweigering zien er op het scherm hetzelfde uit en leiden tot verschillende vervolgstappen.
Een korte reeks die het vernauwt
Begin met de goedkoopste controle en stop bij de eerste stap die niet klopt.
- Wacht op een verse code, dien hem één keer in, en noteer of de uitdaging vóór of ná het accepteren van het wachtwoord verschijnt.
- Vergelijk het label in de authenticator met de gebruikersnaam die de server opslaat.
- Bevestig dat het profiel überhaupt een uitdaging kan beantwoorden, zoals in het
CRV1-geval hierboven. - Vergelijk de klok van het apparaat met een bekende tijdbron; een afwijking van meer dan een paar tientallen seconden breekt TOTP op zichzelf.
- Vraag de operator of het token TOTP of HOTP is, en welke cijfers, periode en hash zijn ingeschreven.
Twee regels voorkomen dat dit het erger maakt. Probeer niet veel keer opnieuw: veel gateways tellen fouten per account en vergrendelen het of beginnen antwoorden te vertragen, zodat een golf een kleine configuratiefout in een supportticket verandert. En schrijf het token niet opnieuw in als diagnose, want dat maakt de oude seed ongeldig; als de echte fout een uitdaging was die de client nooit heeft gestuurd, heb je nu twee wijzigingen om uit te leggen in plaats van één.
Houd de seed en de herstelcodes buiten de kring
De zes cijfers en het geheim erachter zijn niet uitwisselbaar. Een provisioning-QR-code of een Base32-seed genereert elke toekomstige code voor het account, dus die hoort in dezelfde categorie als het wachtwoord: niet in een screenshot, niet in een ticketcommentaar, niet in een chat met iemand die jou eerst benaderde. Herstelcodes zijn een apart mechanisme — eenmalig, slaan de codeprompt vaak helemaal over, en er één uitgeven om het account te testen verwijdert een terugvaloptie die je later nodig kunt hebben.
Een code maakt een loginpagina ook niet betrouwbaar: een OTP-prompt op een gelijkend domein verzamelt een geldige code en speelt hem binnen het venster opnieuw af, en het certificaat is nog steeds wat je vertelt waar je typt.
Als de reeks eindigt bij een profiel dat geen uitdaging kan beantwoorden, repareer het profiel en test opnieuw met één verse code. Als ze eindigt bij niet-passende inschrijfparameters, laat de operator het tokenrecord lezen voordat iemand iets scant. Als ze eindigt bij een vergrendeling, wacht die uit in plaats van van client te wisselen — de accountstatus is de blokkade, niet de app.