Vi mener at Stack Overflow ikke bare bør være en ressurs for veldig spesifikke tekniske spørsmål, men også for generelle retningslinjer for hvordan man løser varianter av vanlige problemer. "Skjemabasert autentisering for nettsteder" bør være et fint tema for et slikt eksperiment.
Vi antar at du allerede vet hvordan du bygger et HTML-skjema for innlogging og passord som sender verdiene til et skript på serversiden for autentisering. Avsnittene nedenfor tar for seg mønstre for god praktisk autentisering, og hvordan du unngår de vanligste sikkerhetsfallgruvene. Til HTTPS eller ikke til HTTPS? Med mindre tilkoblingen allerede er sikker (dvs. tunnelert gjennom HTTPS ved hjelp av SSL/TLS), sendes verdiene i innloggingsskjemaet i klartekst, noe som gjør at alle som avlytter linjen mellom nettleseren og webserveren, kan lese innloggingene underveis. Denne typen avlytting gjøres rutinemessig av myndigheter, men generelt vil vi ikke ta for oss "eide" ledninger annet enn å si dette: Bare bruk HTTPS. Den eneste praktiske* måten å beskytte seg mot avlytting/pakkesniffing under pålogging er å bruke HTTPS eller en annen sertifikatbasert krypteringsmetode (for eksempel TLS) eller en velprøvd og testet challenge-response-metode (for eksempel Diffie-Hellman-basert SRP). Alle andre metoder kan enkelt omgås av en avlyttingsangriper. Hvis du er villig til å være litt upraktisk, kan du selvfølgelig også bruke en form for tofaktorautentisering (f.eks. Google Authenticator-appen, en fysisk kodebok eller en RSA-nøkkelgenerator-dongle). Hvis dette brukes riktig, kan det fungere selv med en usikret tilkobling, men det er vanskelig å forestille seg at en utvikler er villig til å implementere tofaktorautentisering, men ikke SSL. (Ikke) rull din egen JavaScript-kryptering/hashing. På grunn av de antatte (men nå unngåelige) kostnadene og tekniske vanskelighetene med å sette opp et SSL-sertifikat på nettstedet ditt, er noen utviklere fristet til å lage sine egne hashing- eller krypteringsordninger i nettleseren for å unngå å sende innlogginger i klartekst over en usikret linje. Selv om dette er en edel tanke, er det i bunn og grunn ubrukelig (og kan være en sikkerhetsfeil) med mindre det kombineres med noe av det ovennevnte - det vil si enten å sikre linjen med sterk kryptering eller å bruke en velprøvd challenge-response-mekanisme (hvis du ikke vet hva det er, skal du bare vite at det er et av de vanskeligste å bevise, vanskeligste å designe og vanskeligste å implementere konseptene innen digital sikkerhet). Selv om det er sant at hashing av passordet kan være effektivt mot passordavsløring, er det sårbart for replay-angrep, Man-In-The-Middle-angrep/kapring (hvis en angriper kan injisere noen bytes i den usikrede HTML-siden din før den når nettleseren din, kan de ganske enkelt kommentere ut hashing i JavaScript), eller brute-force-angrep (siden du gir angriperen både brukernavn, salt og hashet passord). CAPTCHAS mot menneskeheten. CAPTCHA er ment å avverge én spesifikk kategori av angrep: automatiserte ordbok/brute force trial-and-error-angrep uten menneskelig betjening. Det er ingen tvil om at dette er en reell trussel, men det finnes måter å håndtere den sømløst på som ikke krever CAPTCHA, spesielt riktig utformede innloggingsbegrensningsordninger på serversiden - vi diskuterer disse senere. Vær klar over at CAPTCHA-implementeringer ikke er skapt like; de er ofte ikke løsbare for mennesker, de fleste av dem er faktisk ineffektive mot roboter, alle er ineffektive mot billig arbeidskraft fra den tredje verden (ifølge OWASP er den nåværende sweatshop-prisen 12 dollar per 500 tester), og noen implementeringer kan være teknisk ulovlige i enkelte land (se OWASP Authentication Cheat Sheet). Hvis du må bruke en CAPTCHA, bør du bruke Googles reCAPTCHA, siden den per definisjon er OCR-hard (siden den bruker allerede OCR-misklassifiserte bokskanninger) og prøver veldig hardt å være brukervennlig. Personlig synes jeg at CAPTCHAS er irriterende, og bruker dem bare som en siste utvei når en bruker har mislyktes med å logge inn flere ganger og forsinkelsene er maksimale. Dette skjer sjelden nok til at det er akseptabelt, og det styrker systemet som helhet. Lagring av passord/verifisering av pålogginger. Dette er kanskje endelig allmennkunnskap etter alle de mye omtalte hackene og lekkasjene av brukerdata vi har sett de siste årene, men det må sies: Ikke lagre passord i klartekst i databasen din. Brukerdatabaser blir rutinemessig hacket, lekket eller stjålet ved hjelp av SQL-injeksjon, og hvis du lagrer passord i klartekst, er det slutt på innloggingssikkerheten. Så hvis du ikke kan lagre passordet, hvordan kontrollerer du at kombinasjonen av innlogging og passord som POSTES fra innloggingsskjemaet, er korrekt? Svaret er hashing ved hjelp av en key derivation function. Hver gang en ny bruker opprettes eller et passord endres, tar du passordet og kjører det gjennom en KDF, for eksempel Argon2, bcrypt, scrypt eller PBKDF2, og gjør klartekstpassordet ("correcthorsebatterystaple") om til en lang, tilfeldig streng, som er mye tryggere å lagre i databasen. For å verifisere en pålogging kjører du den samme hash-funksjonen på passordet, denne gangen med saltet, og sammenligner den resulterende hash-strengen med verdien som er lagret i databasen. Argon2, bcrypt og scrypt lagrer allerede saltet sammen med hashen. Se denne artikkelen på sec.stackexchange for mer detaljert informasjon. Grunnen til at et salt brukes, er at hashing i seg selv ikke er tilstrekkelig - du må legge til et såkalt 'salt' for å beskytte hashen mot rainbow tables. Et salt forhindrer effektivt at to passord som er nøyaktig like, lagres som samme hashverdi, og forhindrer dermed at hele databasen skannes i én kjøring hvis en angriper utfører et angrep for å gjette passord. En kryptografisk hash bør ikke brukes til lagring av passord fordi brukervalgte passord ikke er sterke nok (dvs. vanligvis ikke inneholder nok entropi), og en angriper som har tilgang til hashverdiene, kan gjette seg frem til et passord på relativt kort tid. Dette er grunnen til at KDF-er brukes - disse "strekker ut nøkkelen", noe som betyr at hver gang en angriper gjetter et passord, gjentas hash-algoritmen flere ganger, for eksempel 10 000 ganger, noe som gjør at angriperen gjetter passordet 10 000 ganger langsommere. Sesjonsdata - "Du er logget inn som Spiderman69". Når serveren har verifisert påloggingen og passordet mot brukerdatabasen og funnet en match, må systemet huske at nettleseren er autentisert. Denne informasjonen skal bare lagres på serversiden i øktdataene. Hvis du ikke er kjent med øktdata, kan du lese om hvordan det fungerer: En enkelt tilfeldig generert streng lagres i en informasjonskapsel som utløper, og brukes til å referere til en samling data - øktdataene - som lagres på serveren. Hvis du bruker et MVC-rammeverk, er dette utvilsomt allerede håndtert. Hvis det i det hele tatt er mulig, må du sørge for at øktinformasjonskapselen har sikkerhets- og HTTP Only-flagg når den sendes til nettleseren. HttpOnly-flagget gir en viss beskyttelse mot at informasjonskapselen leses gjennom XSS-angrep. Det sikre flagget sørger for at informasjonskapselen bare sendes tilbake via HTTPS, og beskytter derfor mot angrep fra nettverkssniffing. Verdien av informasjonskapselen skal ikke være forutsigbar. Hvis det vises en informasjonskapsel som refererer til en ikke-eksisterende økt, bør verdien erstattes umiddelbart for å forhindre øktfiksering.
Vedvarende påloggingsinformasjonskapsler ("husk meg" funksjonalitet) er en faresone; på den ene siden er de like sikre som vanlige pålogginger når brukerne forstår hvordan de skal håndteres, og på den andre siden utgjør de en enorm sikkerhetsrisiko i hendene på uforsiktige brukere, som kan bruke dem på offentlige datamaskiner og glemme å logge ut, og som kanskje ikke vet hva informasjonskapsler er eller hvordan de skal slettes. Personlig liker jeg faste innlogginger for de nettstedene jeg besøker regelmessig, men jeg vet hvordan jeg skal håndtere dem på en sikker måte. Hvis du er sikker på at brukerne dine vet det samme, kan du bruke faste innlogginger med god samvittighet. Hvis ikke - ja, da kan du kanskje mene at brukere som er uforsiktige med påloggingsinformasjonen sin, selv er skyld i at de blir hacket. Det er jo ikke slik at vi går hjem til brukerne våre og river av dem alle Post-It-lappene med passord som de har hengt opp på kanten av skjermen. Noen systemer har selvsagt ikke råd til at noen kontoer blir hacket, og i slike systemer kan det ikke forsvares å ha vedvarende pålogginger. **Hvis du bestemmer deg for å implementere permanente påloggingscookies, gjør du det på følgende måte
**Ikke implementer "hemmelige spørsmål". Funksjonen "hemmelige spørsmål" er et sikkerhetsmessig anti-mønster. Les artikkelen fra lenke nummer 4 på MÅ-LES-listen. Det kan du spørre Sarah Palin om, etter at Yahoo! e-postkontoen hennes ble hacket under en tidligere presidentvalgkamp fordi svaret på sikkerhetsspørsmålet hennes var ... "Wasilla High School"! Selv med brukerspesifiserte spørsmål er det svært sannsynlig at de fleste brukere vil velge enten eller:
Jeg har allerede nevnt hvorfor du aldri bør bruke sikkerhetsspørsmål for å håndtere glemte/tapte brukerpassord; det sier seg også selv at du aldri bør sende brukerne deres faktiske passord via e-post. Det er minst to andre altfor vanlige fallgruver å unngå på dette området:
Først bør du lese denne lille artikkelen for å få en realitetssjekk: De 500 vanligste passordene. Ok, listen er kanskje ikke den kanoniske listen over de vanligste passordene på noen systemer noen steder noensinne, men den gir en god indikasjon på hvor dårlig folk velger passord når det ikke finnes noen håndhevede retningslinjer. I tillegg ser listen skremmende lik ut når du sammenligner den med offentlig tilgjengelige analyser av nylig stjålne passord. Så..: Uten minimumskrav til passordstyrke bruker 2 % av brukerne et av de 20 vanligste passordene. Det betyr at hvis en angriper bare får 20 forsøk, vil 1 av 50 kontoer på nettstedet ditt kunne knekkes. For å hindre dette må man beregne entropien til et passord og deretter bruke en terskelverdi. National Institute of Standards and Technology (NIST) Special Publication 800-63 har et sett med svært gode forslag. Når dette kombineres med en analyse av ordbok og tastaturoppsett (for eksempel 'qwertyuiop' er et dårlig passord), kan det avvise 99 % av alle dårlig valgte passord på et nivå på 18 bits entropi. Å bare beregne passordstyrken og vise en visuell styrkemåler til brukeren er bra, men ikke tilstrekkelig. Hvis det ikke håndheves, vil mange brukere sannsynligvis ignorere det. Randall Munroe's Password Strength xkcd anbefales på det sterkeste for et forfriskende syn på brukervennligheten til passord med høy entropi. Bruk Troy Hunt's Have I Been Pwned API til å sjekke brukernes passord mot passord som er kompromittert i offentlige datainnbrudd.
Ta først en titt på tallene: Passordgjenopprettingshastigheter - Hvor lenge vil passordet ditt holde seg. Hvis du ikke har tid til å se gjennom tabellene i den lenken, finner du en liste over dem her:
Mer avanserte angripere vil for øvrig forsøke å omgå innloggingsbegrensningen ved å spre aktivitetene sine:
Legitimasjon kan komme på avveie, enten det er ved å bli utnyttet, ved at passord skrives ned og mistes, ved at bærbare datamaskiner med nøkler blir stjålet, eller ved at brukere logger seg inn på phishing-sider. Innlogginger kan beskyttes ytterligere med tofaktorautentisering, som bruker faktorer utenfor båndet, for eksempel engangskoder som mottas via en telefonsamtale, SMS-melding, app eller dongle. Flere leverandører tilbyr tjenester for tofaktorautentisering. Autentiseringen kan delegeres fullstendig til en tjeneste for enkel pålogging, der en annen leverandør håndterer innsamlingen av legitimasjon. Dermed overlates problemet til en pålitelig tredjepart. Google og Twitter tilbyr begge standardbaserte SSO-tjenester, mens Facebook har en lignende proprietær løsning.
Den eneste praktiske måten å sende legitimasjon 100 % sikkert på, er å bruke SSL. Det er ikke sikkert å bruke JavaScript til å hashe passordet. Vanlige fallgruver ved hashing av passord på klientsiden:
Du må aldri lagre passord i klartekst i databasen. Ikke engang hvis du ikke bryr deg om sikkerheten på ditt eget nettsted. Anta at noen av brukerne dine vil gjenbruke passordet til nettbankkontoen sin. Så lagre det hashede passordet og kast originalen. Og sørg for at passordet ikke vises i tilgangslogger eller applikasjonslogger. OWASP anbefaler bruk av Argon2 som førstevalg for nye applikasjoner. Hvis dette ikke er tilgjengelig, bør PBKDF2 eller scrypt brukes i stedet. Og til slutt, hvis ingen av de ovennevnte er tilgjengelige, bruk bcrypt. Hashes i seg selv er også usikre. For eksempel er identiske passord ensbetydende med identiske hasher - dette gjør hash-oppslagstabeller til en effektiv måte å knekke mange passord samtidig på. I stedet bør du lagre den saltede hashen. Et salt er en streng som legges til passordet før hashing - bruk et forskjellig (tilfeldig) salt for hver bruker. Saltet er en offentlig verdi, så du kan lagre dem sammen med hashen i databasen. Se her for mer informasjon om dette. Dette betyr at du ikke kan sende brukeren de glemte passordene (fordi du bare har hashen). Ikke tilbakestill brukerens passord med mindre du har autentisert brukeren (brukerne må bevise at de er i stand til å lese e-poster som sendes til den lagrede (og validerte) e-postadressen).
Sikkerhetsspørsmål er usikre - unngå å bruke dem. Unngå å bruke dem. Alt et sikkerhetsspørsmål gjør, gjør et passord bedre. Les DEL III: Bruk av hemmelige spørsmål i @Jens Rolands svar her i denne wikien.
Etter at brukeren har logget inn, sender serveren en øktinformasjonskapsel til brukeren. Serveren kan hente brukernavn eller id fra informasjonskapselen, men ingen andre kan generere en slik informasjonskapsel (TODO forklare mekanismer). Informasjonskapsler kan kapres: De er bare like sikre som resten av klientens maskin og annen kommunikasjon. De kan leses fra harddisken, sniffes i nettverkstrafikken, stjeles ved hjelp av et cross-site scripting-angrep, phishing fra en forgiftet DNS slik at klienten sender informasjonskapslene sine til feil servere. Ikke send vedvarende informasjonskapsler. Informasjonskapsler bør utløpe når klientøkten avsluttes (nettleseren lukkes eller domenet forlates). Hvis du ønsker å autologinere brukerne dine, kan du angi en vedvarende informasjonskapsel, men den bør være forskjellig fra en informasjonskapsel for hele økten. Du kan sette et ekstra flagg om at brukeren er automatisk pålogget og må logge inn på ekte for sensitive operasjoner. Dette er populært blant shoppingsider som ønsker å gi deg en sømløs, personlig shoppingopplevelse, men som samtidig ønsker å beskytte de økonomiske opplysningene dine. Når du for eksempel besøker Amazon, viser de deg en side som ser ut som om du er logget inn, men når du skal legge inn en bestilling (eller endre leveringsadresse, kredittkort osv.), ber de deg om å bekrefte passordet ditt. Finansielle nettsteder som banker og kredittkort har derimot bare sensitive data og bør ikke tillate automatisk pålogging eller en lavsikkerhetsmodus.
Først vil jeg ta forbehold om at dette svaret ikke er det beste svaret på akkurat dette spørsmålet. Det bør definitivt ikke være det beste svaret!
Jeg går videre og nevner Mozillas foreslåtte BrowserID (eller kanskje mer presist Verified Email Protocol) i den hensikt å finne en oppgraderingsvei til bedre tilnærminger til autentisering i fremtiden.
Jeg vil oppsummere det på denne måten:
@
domene" er kortfattet og støttes av en lang rekke protokoller og URI-ordninger. En slik identifikator er selvfølgelig mest universelt anerkjent som en e-postadresse.Dette er ikke strengt tatt "skjemabasert autentisering for nettsteder". Men det er et forsøk på å gå fra den nåværende normen med skjemabasert autentisering til noe sikrere: nettleserstøttet autentisering.