De definitieve gids voor formuliergebaseerde websiteauthenticatie
Form-based authenticatie voor websites
Wij geloven dat Stack Overflow niet alleen een bron zou moeten zijn voor zeer specifieke technische vragen, maar ook voor algemene richtlijnen over hoe variaties op veelvoorkomende problemen op te lossen. "Form-based authentication for websites" zou een prima onderwerp moeten zijn voor zo'n experiment.
Het zou onderwerpen moeten bevatten zoals:
- Hoe in te loggen
- Hoe uitloggen
- Hoe ingelogd blijven
- Cookies beheren (inclusief aanbevolen instellingen)
- SSL/HTTPS encryptie
- Hoe wachtwoorden op te slaan
- Geheime vragen gebruiken
- Vergeten gebruikersnaam/wachtwoord functionaliteit
- Gebruik van nonces om cross-site request forgeries (CSRF) te voorkomen
- OpenID
- "Onthoud mij" selectievakje
- Browser autocompletie van gebruikersnamen en wachtwoorden
- Geheime URL's (openbare URL beschermd door digest)
- Controle van wachtwoordsterkte
- E-mail validatie
- en nog veel meer over formuliergebaseerde authenticatie...
Het zou geen dingen moeten bevatten zoals:
- Rollen en autorisatie
- HTTP basis authenticatie
Help ons alstublieft door:
- Subonderwerpen voor te stellen
- Goede artikelen over dit onderwerp in te zenden
- Bewerken van het officiële antwoord
5304
3
DEEL I: Hoe in te loggen
We'nemen aan dat je al weet hoe je een login+wachtwoord HTML formulier bouwt dat de waarden POST naar een script aan de server kant voor authenticatie. De secties hieronder zullen gaan over patronen voor goede praktische auth, en hoe je de meest voorkomende veiligheids valkuilen kunt vermijden. *To HTTPS or not to HTTPS? Tenzij de verbinding al beveiligd is (dat wil zeggen, getunneld door HTTPS met behulp van SSL / TLS), zal uw login-formulier waarden worden verzonden in duidelijke tekst, waardoor iedereen die afluistert op de lijn tussen browser en webserver in staat zal zijn om logins te lezen als ze passeren. Dit soort afluisteren wordt routinematig gedaan door overheden, maar in het algemeen zullen we'niet ingaan op 'owned' afluisterpraktijken anders dan dit te zeggen: Gebruik gewoon HTTPS. In essentie is de enige praktische* manier om je te beschermen tegen afluisteren/packet sniffing tijdens het inloggen door gebruik te maken van HTTPS of een ander certificaat-gebaseerd encryptie schema (bijvoorbeeld, [TLS][1]) of een bewezen & getest challenge-response schema (bijvoorbeeld, het [Diffie-Hellman][2]-gebaseerde SRP). Elke andere methode kan gemakkelijk omzeild worden door een afluisterende aanvaller. Natuurlijk, als je bereid bent om een beetje onpraktisch te worden, zou je ook een vorm van twee-factor authenticatie kunnen gebruiken (b.v. de Google Authenticator app, een fysiek 'cold war style' codeboek, of een RSA sleutelgenerator dongle). Indien correct toegepast, zou dit zelfs kunnen werken met een onbeveiligde verbinding, maar het is moeilijk voor te stellen dat een ontwikkelaar bereid zou zijn om twee-factor auth te implementeren maar geen SSL. (Niet) Roll-your-own JavaScript encryptie/hashing Gezien de waargenomen (hoewel nu [vermijdbaar][27]) kosten en technische moeilijkheid van het opzetten van een SSL-certificaat op uw website, komen sommige ontwikkelaars in de verleiding om hun eigen hashing- of encryptieschema's in de browser te gebruiken om te vermijden dat logins in klare tekst over een onbeveiligde draad worden doorgegeven. Hoewel dit een nobele gedachte is, is het in wezen nutteloos (en kan het een [veiligheidsfout][3] zijn) tenzij het wordt gecombineerd met een van de bovenstaande - dat wil zeggen, ofwel het beveiligen van de lijn met sterke encryptie of het gebruik van een beproefd challenge-response mechanisme (als je niet weet wat dat is, weet dan dat het een van de moeilijkst te bewijzen, moeilijkst te ontwerpen, en moeilijkst te implementeren concepten in digitale veiligheid is). Hoewel het hashen van het wachtwoord effectief kan zijn tegen wachtwoordopenbaarmaking, is het kwetsbaar voor replay-aanvallen, Man-In-The-Middle-aanvallen / hijackings (als een aanvaller een paar bytes in uw onbeveiligde HTML-pagina kan injecteren voordat deze uw browser bereikt, kunnen ze eenvoudigweg de hashing in het JavaScript uitcommentariëren), of brute-force-aanvallen (aangezien u de aanvaller zowel gebruikersnaam, zout als het gehashte wachtwoord geeft). CAPTCHAS tegen de mensheid [CAPTCHA][4] is bedoeld om één specifieke aanvalscategorie tegen te gaan: geautomatiseerde dictionary/brute force trial-and-error zonder menselijke operator. Er is geen twijfel dat dit een reële bedreiging is, echter, er zijn manieren om er naadloos mee om te gaan die geen CAPTCHA vereisen, specifiek goed ontworpen server-side login throttling schema's - we'zullen die later bespreken. Weet dat CAPTCHA implementaties niet gelijk geschapen zijn; ze zijn vaak'niet door mensen op te lossen, de meeste zijn eigenlijk ineffectief tegen bots, ze zijn allemaal ineffectief tegen goedkope derde-wereld arbeid (volgens [OWASP][5], is het huidige sweatshop tarief $12 per 500 tests), en sommige implementaties kunnen technisch illegaal zijn in sommige landen (zie [OWASP Authentication Cheat Sheet][6]). Als u een CAPTCHA moet gebruiken, gebruik dan Google's [reCAPTCHA][7], omdat het per definitie OCR-hard is (omdat het reeds OCR-geclassificeerde boekscans gebruikt) en erg zijn best doet om gebruikersvriendelijk te zijn. Persoonlijk vind ik CAPTCHAS vervelend, en gebruik ik ze alleen als laatste redmiddel wanneer een gebruiker er een aantal keren niet in geslaagd is in te loggen en de vertragingen maximaal zijn. Dit zal zelden genoeg gebeuren om aanvaardbaar te zijn, en het versterkt het systeem in zijn geheel. Het opslaan van wachtwoorden / verifiëren van logins Dit mag dan eindelijk algemeen bekend zijn na alle geruchtmakende hacks en lekken van gebruikersgegevens die we de afgelopen jaren hebben gezien, maar het moet gezegd worden: Sla wachtwoorden niet in duidelijke tekst op in uw database. Gebruikersdatabases worden routinematig gehackt, gelekt of ontfutseld via SQL-injectie, en als u ruwe, onversleutelde wachtwoorden opslaat, is dat meteen einde verhaal voor uw aanmeldingsbeveiliging. Dus als je het wachtwoord niet kunt opslaan, hoe controleer je dan dat de login+wachtwoord combinatie POSTed van het loginformulier correct is? Het antwoord is hashing met behulp van een [sleutelafleidingsfunctie][24]. Telkens wanneer een nieuwe gebruiker wordt aangemaakt of een wachtwoord wordt gewijzigd, neemt u het wachtwoord en voert het door een KDF, zoals Argon2, bcrypt, scrypt of PBKDF2, waardoor het klare wachtwoord ("correcthorsebatterystaple") wordt omgezet in een lange, willekeurig uitziende string, die een stuk veiliger is om in uw database op te slaan. Om een login te verifiëren, voert u dezelfde hash-functie uit op het ingevoerde wachtwoord, deze keer met de salt en vergelijkt u de resulterende hash-string met de waarde die in uw database is opgeslagen. Argon2, bcrypt en scrypt slaan het zout al met de hash op. Bekijk dit [artikel][23] op sec.stackexchange voor meer gedetailleerde informatie. De reden dat een zout wordt gebruikt is dat hashing op zichzelf niet voldoende is -- u'zult een zogenaamd 'salt' willen toevoegen om de hash te beschermen tegen [rainbow tables][8]. Een zout voorkomt effectief dat twee wachtwoorden die precies overeenkomen worden opgeslagen als dezelfde hashwaarde, waardoor wordt voorkomen dat de hele database in één keer wordt gescand als een aanvaller een wachtwoord-raad-aanval uitvoert. Een cryptografische hash mag niet worden gebruikt voor de opslag van wachtwoorden, omdat door de gebruiker gekozen wachtwoorden niet sterk genoeg zijn (d.w.z. meestal niet genoeg entropie bevatten) en een aanvaller met toegang tot de hashes een aanval om wachtwoorden te raden in relatief korte tijd zou kunnen uitvoeren. Daarom worden KDF's gebruikt - deze ["stretch the key"][25], wat betekent dat elke keer dat een aanvaller een wachtwoord raadt, dit leidt tot meerdere herhalingen van het hash-algoritme, bijvoorbeeld 10.000 keer, waardoor de aanvaller het wachtwoord 10.000 keer langzamer raadt. Sessiegegevens - "U bent ingelogd als Spiderman69"** Zodra de server de login en het wachtwoord heeft geverifieerd met uw gebruikersdatabase en een overeenkomst heeft gevonden, heeft het systeem een manier nodig om te onthouden dat de browser is geauthenticeerd. Dit feit moet alleen worden opgeslagen op de server in de sessie gegevens.
Definitief Artikel
Verzend referenties
De enige praktische manier om referenties 100% veilig te versturen is door gebruik te maken van [SSL][1]. Het gebruik van JavaScript om het wachtwoord te hashen is niet veilig. Veel voorkomende valkuilen voor client-side wachtwoord hashing:
Het opslaan van wachtwoorden
Sla nooit wachtwoorden op als platte tekst in de database. Zelfs niet als u niet geeft om de veiligheid van uw eigen site. Ga ervan uit dat sommige van uw gebruikers het wachtwoord van hun online bankrekening zullen hergebruiken. Dus, sla het gehashte wachtwoord op, en gooi het origineel weg. En zorg ervoor dat het wachtwoord niet opduikt in toegangslogs of toepassingslogs. OWASP beveelt het gebruik van Argon2 aan als eerste keuze voor nieuwe applicaties. Als dit niet beschikbaar is, moet in plaats daarvan PBKDF2 of scrypt worden gebruikt. En tenslotte, als geen van bovenstaande beschikbaar is, gebruik dan bcrypt. Hashes op zichzelf zijn ook onveilig. Bijvoorbeeld, identieke wachtwoorden betekenen identieke hashes--dit maakt hash lookup tables een effectieve manier om veel wachtwoorden in een keer te kraken. Sla in plaats daarvan de gesaldeerde hash op. Een zout is een tekenreeks die aan het wachtwoord wordt toegevoegd voor het hashen - gebruik een ander (willekeurig) zout per gebruiker. De salt is een publieke waarde, dus u kunt ze samen met de hash in de database opslaan. Zie hier voor meer hierover. Dit betekent dat je'niet hun vergeten wachtwoorden naar de gebruiker kunt sturen (omdat je alleen de hash hebt). Reset het wachtwoord van de gebruiker niet tenzij u de gebruiker hebt geauthenticeerd (gebruikers moeten bewijzen dat ze in staat zijn om e-mails te lezen die naar het opgeslagen (en gevalideerde) e-mailadres zijn verzonden).
Beveiligingsvragen
Veiligheidsvragen zijn onveilig - vermijd het gebruik ervan. Waarom? Alles wat een beveiligingsvraag doet, doet een wachtwoord beter. Lees DEEL III: Geheime vragen gebruiken in [@Jens Roland antwoord][6] hier in deze wiki.
Sessie-cookies
Nadat de gebruiker inlogt, stuurt de server de gebruiker een sessie cookie. De server kan de gebruikersnaam of id uit de cookie halen, maar niemand anders kan zo'n cookie genereren (TODO leg mechanismen uit). [Cookies kunnen worden gekaapt][7]: ze zijn slechts zo veilig als de rest van de machine van de client's en andere communicatie. Ze kunnen van schijf worden gelezen, in netwerkverkeer worden gesnuffeld, door een cross-site scripting aanval worden gelicht, via een vergiftigde DNS worden gephisht zodat de client zijn cookies naar de verkeerde servers stuurt. Stuur geen persistente cookies. Cookies moeten verlopen aan het einde van de client sessie (browser sluiten of uw domein verlaten). Als u uw gebruikers wilt autologineren, kunt u een persistent cookie instellen, maar het moet verschillend zijn van een full-session cookie. Je kunt een extra vlag instellen die aangeeft dat de gebruiker automatisch is ingelogd, en echt moet inloggen voor gevoelige operaties. Dit is populair bij winkelsites die u een naadloze, gepersonaliseerde winkelervaring willen bieden maar toch uw financiële gegevens willen beschermen. Bijvoorbeeld, wanneer u terugkeert om Amazon te bezoeken, tonen zij u een pagina die eruit ziet alsof u'bent ingelogd, maar wanneer u een bestelling gaat plaatsen (of uw verzendadres, kredietkaart enz. wijzigt), vragen zij u om uw wachtwoord te bevestigen. Financiële websites, zoals banken en creditcards, hebben daarentegen alleen gevoelige gegevens en zouden geen auto-login of een laagbeveiligde modus moeten toestaan.
Lijst van externe bronnen
Ten eerste, een sterk voorbehoud dat dit antwoord niet het beste is voor deze exacte vraag. Het moet zeker niet het beste antwoord zijn!
Ik zal Mozilla's voorgestelde BrowserID (of misschien meer precies, het Verified Email Protocol) gaan noemen in de geest van het vinden van een upgrade pad naar betere benaderingen van authenticatie in de toekomst.
Ik zal het zo samenvatten:
@
domain" is beknopt en wordt ondersteund door een breed scala van protocollen en URI-schema's. Een dergelijke identifier wordt natuurlijk het meest universeel herkend als een e-mailadres.Dit is niet echt "formuliergebaseerde authenticatie voor websites". Maar het is een poging om van de huidige norm van formuliergebaseerde authenticatie over te stappen op iets veiligers: browser-ondersteunde authenticatie.