javascript - Er det trygt å lagre en JWT i localStorage med ReactJS?
Jeg bygger for øyeblikket en enkeltsideapplikasjon ved hjelp av ReactJS.
Jeg leste at en av grunnene til å ikke bruke localStorage er på grunn av XSS-sårbarheter.
Siden React unngår alle brukerinnspill, ville det nå være trygt å bruke localStorage?
Svar #1
I de fleste moderne enkeltsideapplikasjoner må vi faktisk lagre tokenet et sted på klientsiden (det mest vanlige brukstilfellet er å holde brukeren logget inn etter en oppdatering av siden).
Det er totalt 2 tilgjengelige alternativer: Weblagring (session storage, local storage) og en klient-side cookie. Begge alternativene er mye brukt, men dette betyr ikke at de er veldig sikre.
Tom Abbott oppsummerer godt sikkerheten til JWT sessionStorage og localStorage:
Weblagring (localStorage/sessionStorage) er tilgjengelig via JavaScript på samme domene. Dette betyr at all JavaScript som kjører på nettstedet ditt, vil ha tilgang til weblagring, og på grunn av dette kan være sårbar for cross-site scripting (XSS)-angrep. XSS, kort fortalt, er en type sårbarhet hvor en angriper kan injisere JavaScript som vil kjøre på siden din. Enkle XSS-angrep forsøker å injisere JavaScript gjennom skjemaer, hvor angriperen setter inn
<script>alert('You are Hacked');</script>i et skjema for å se om det kjøres av nettleseren og kan sees av andre brukere.
For å forhindre XSS, er det vanlige svaret å escape og kode alle ikke-pålitelige data. React gjør (for det meste) det for deg! Her er en flott diskusjon om hvor mye XSS-sårbarhetsbeskyttelse React er ansvarlig for.
Men det dekker ikke alle mulige sårbarheter! En annen potensiell trussel er bruk av JavaScript som ligger på CDN-er eller utenfor infrastrukturen.
Her er Tom igjen:
Moderne nettapper inkluderer tredjeparts JavaScript-biblioteker for A/B-testing, trakt-/markedsanalyse og annonser. Vi bruker pakkebehandlere som Bower for å importere andres kode inn i appene våre.
Hva om bare ett av skriptene du bruker er kompromittert? Ondsinnet JavaScript kan være innebygd på siden, og Web Storage er kompromittert. Disse typene XSS-angrep kan få tak i alles Web Storage som besøker nettstedet ditt, uten deres kunnskap. Dette er sannsynligvis grunnen til at mange organisasjoner råder mot å lagre noe av verdi eller stole på informasjon i web storage. Dette inkluderer sesjonsidentifikatorer og tokens.
Derfor er min konklusjon at som en lagringsmekanisme pålegger Web Storage ingen sikre standarder under overføring. Den som leser Web Storage og bruker det må gjøre sin aktsomhet for å sikre at de alltid sender JWT over HTTPS og aldri HTTP.
Svar #2
Grundleggende er det greit å lagre JWT-en din i localStorage.
Og jeg tror dette er en god måte. Hvis vi snakker om XSS, XSS som bruker CDN, er det også en potensiell risiko for å få tak i klientens innlogging/passord. Å lagre data i lokal lagring vil i det minste forhindre CSRF-angrep.
Du må være oppmerksom på begge og velge hva du vil. Begge angrep er ikke alt du trenger å være oppmerksom på, bare husk: HELE APPEN DIN ER BARE SÅ SIKKER SOM DET MEST USIKRE PUNKTET I APPEN DIN.
Å lagre igjen er greit, å være sårbar for XSS, CSRF,... er det ikke
Svar #3
Jeg vet at dette er et gammelt spørsmål, men i henhold til det @mikejones1477 sa, så eskaper moderne frontend-biblioteker og rammeverk teksten og gir deg beskyttelse mot XSS. Grunnen til at cookies ikke er en sikker metode for å bruke legitimasjon er at cookies ikke forhindrer CSRF, mens localStorage gjør det (husk også at cookies er tilgjengelige for JavaScript, så XSS er ikke det store problemet her), dette svaret oppsummerer hvorfor.
Grunnen til at lagring av en autentiseringstoken i lokal lagring og manuelt legge den til hver forespørsel beskytter mot CSRF er det nøkkelordet: manuelt. Siden nettleseren ikke automatisk sender den autentiseringstokenen, hvis jeg besøker
evil.exampleog det klarer å sende en POSThttp://example.com/delete-my-account, vil det ikke kunne sende min autentiseringstoken, så forespørselen blir ignorert.
Selvfølgelig er httpOnly den hellige gral, men du kan ikke få tilgang fra reactjs eller noen JS-rammeverk, dessuten har du fortsatt CSRF-sårbarhet. Min anbefaling vil være localstorage, eller hvis du vil bruke cookies, sørg for å implementere en løsning på CSRF-problemet ditt slik Django gjør.
Når det gjelder CDN-er, sørg for at du ikke bruker en merkelig CDN, for eksempel CDN som Google eller Bootstrap tilbyr, som vedlikeholdes av fellesskapet og ikke inneholder skadelig kode. Hvis du ikke er sikker, står du fritt til å gjennomgå den.
Svar #4
Jeg er bekymret for alle svarene som antyder at man ikke bør lagre i lokal lagring, da dette er utsatt for et XSS-angrep eller et ondsinnet bibliotek. Noen av disse går til og med inn i lange diskusjoner, selv om svaret er ganske lite/enkel, noe jeg vil komme til om kort tid.
Å foreslå det er det samme som å si "Ikke bruk en stekepanne til å lage maten din fordi hvis du en natt blir full og bestemmer deg for å steke, vil du ende opp med å brenne deg selv og huset ditt". Hvis JWT blir lekket på grunn av et XSS-angrep eller et ondsinnet bibliotek, har nettstedseieren et større problem: deres nettsted er sårbart for XSS-angrep eller bruker et ondsinnet bibliotek.
Svaret: hvis du er sikker på at nettstedet ditt ikke har disse sårbarhetene, gå for det.
Ref: https://auth0.com/docs/security/data-security/token-storage#browser-local-storage-scenarios
Svar #5
En ting å huske på er om JWT-ene er:
- Første part (dvs. bare for å få tilgang til dine egne serverkommandoer)
- Tredjepart (dvs. en JWT for Google, Facebook, Twitter, osv.)
Hvis JWT er fra førstepartei:
Da spiller det ikke så stor rolle om du lagrer JWT-en i lokal lagring, eller i en sikret cookie (dvs. HttpOnly, SameSite=strict, og secure) [forutsatt at nettstedet ditt allerede bruker HTTPS, noe det bør].
Dette er fordi, hvis man antar at et XSS-angrep lykkes (dvs. en angriper klarte å sette inn Javascript-kode gjennom en JS-avhengighet som nå kjører på alle besøkendes nettlesere), er det uansett «game over»; alle kommandoene som var ment å sikres av «JWT-token-verifiseringene», kan nå utføres av angriperen bare ved å få skriptet de har satt inn i frontend-JS til å kalle alle nødvendige endepunkter. Selv om de ikke kan lese JWT-tokenet selv (på grunn av cookie-ens http-only-flag), spiller det ingen rolle fordi de bare kan sende alle nødvendige kommandoer, og nettleseren vil gladelig sende JWT-tokenet sammen med disse kommandoene.
Nå, selv om XSS-angrepssituasjonen kan sies å være «game over» uansett (enten det er lokal lagring eller sikret informasjonskapsel), er informasjonskapsler fortsatt litt bedre, fordi angriperen kun kan utføre angrepene hvis/når brukeren har nettstedet åpent i nettleseren sin.
Dette forårsaker følgende "irritasjoner" for angriperen:
- "Min XSS-injeksjon fungerte! Greit, tid for å samle inn private data om sjefen min og bruke det som utpressing. Pokker! Han logger seg bare inn mens jeg er her på jobb. Jeg må forberede all koden min på forhånd, og få den til å kjøre innen de tre minuttene han er der, i stedet for å kunne utforske dataene hans på plattformen på en mer gradvis/utforskende måte."
- "Min XSS-injeksjon fungerte! Nå kan jeg endre koden slik at alle Bitcoin-overføringer går til meg i stedet! Jeg har ikke noe spesielt mål i tankene, så jeg trenger ikke å vente på noen. Mann, jeg skulle ønske jeg kunne få tilgang til JWT-tokenet selv - på den måten kunne jeg stille og rolig samle dem alle, og deretter tømme alles lommebøker på en gang. Med disse cookie-beskyttede JWT-ene, kan det hende jeg bare klarer å kapre noen dusin besøkende før utviklerne finner ut av det og stopper overføringene..."
- "Min XSS-injeksjon fungerte! Dette vil gi meg tilgang til selv dataene som bare adminene kan se. Hmmm, dessverre må jeg gjøre alt gjennom brukerens nettleser. Jeg er ikke sikker på at det finnes en realistisk måte for meg å laste ned disse 3 GB-filene på ved å bruke dette; jeg starter nedlastingen, men det oppstår minneproblemer, og brukeren lukker alltid nettstedet før det er ferdig! I tillegg er jeg bekymret for at klient-side-overføringer av denne størrelsen kan bli oppdaget av noen."
Hvis JWT er fra en tredjepart:
I dette tilfellet avhenger det virkelig av hva tredjeparts JWT-er tillater innehaveren å gjøre.
Hvis alt de gjør er å la noen "få tilgang til grunnleggende profilinformasjon" på hver bruker, så er det ikke så farlig hvis angripere kan få tilgang til det; noen e-poster kan lekke, men angriperen kunne sannsynligvis fått det uansett ved å navigere til brukerens "kontoside" hvor disse dataene vises i brukergrensesnittet. (å ha JWT-tokenet lar dem bare unngå de "irritasjonene" som ble nevnt i forrige seksjon)
Hvis tredjeparts JWT-er derimot lar deg gjøre mer omfattende ting -- for eksempel å ha full tilgang til deres skylagringsdata, sende meldinger på tredjepartsplattformer, lese private meldinger på tredjepartsplattformer, osv., så er det faktisk betydelig verre å ha tilgang til JWT-ene enn bare å kunne "sende autentiserte kommandoer".
Dette er fordi når angriperen ikke kan få tilgang til den faktiske JWT, må de rute alle kommandoer gjennom din førstepartsserver. Dette har følgende fordeler:
Begrensede kommandoer: Fordi alle kommandoene går gjennom serveren din, kan angripere bare utføre det delsettet av kommandoer som serveren din er bygget for å håndtere. For eksempel, hvis serveren din bare noen gang leser/skriver fra en bestemt mappe i en brukers skylagring, har angriperen de samme begrensningene.
Enklere oppdagelse: Fordi alle kommandoene går gjennom serveren din, kan du kanskje legge merke til (gjennom logger, plutselig økning i kommandoer, osv.) at noen har utviklet et XSS-angrep. Dette lar deg potensielt fikse det raskere. (hvis de hadde JWT-ene selv, kunne de stille og rolig utført kall til tredjepartsplattformene, uten å måtte kontakte serverne dine i det hele tatt)
Flere måter å identifisere angriperen på: Fordi kommandoene går gjennom serveren din, vet du nøyaktig når kommandoene blir sendt, og hvilken IP-adresse som brukes for å sende dem. I noen tilfeller kan dette hjelpe deg med å identifisere hvem som utfører angrepene. IP-adressen er den mest åpenbare måten, selv om de fleste angripere som er i stand til XSS-angrep sannsynligvis er nok klar over å bruke en proxy.
En mer avansert identifikasjonsmetode kan være å, for eksempel, få opp en spesiell melding som er unik for hver bruker (eller i det minste delt inn i grupper), av en slik art at angriperen (når han åpner nettstedet fra sin egen konto) vil se den meldingen, og prøve å kjøre en ny kommando basert på den. For eksempel kan du lenke til et "falskt utviklerblogginnlegg" som snakker om noen "nye API-er" du introduserer, som lar brukere få tilgang til enda mer av deres private data; det listige er at URL-en for den "nye API-en" er forskjellig for hver bruker som ser blogginnlegget, slik at når API-et forsøkes brukt (mot offeret), vet du nøyaktig hvem som gjorde det. Selvfølgelig forutsetter dette ideen om at angriperen har en "ekte konto" på nettstedet sammen med offeret, og kan bli fristet/lurt av denne typen tilnærming (for eksempel vil det ikke fungere hvis angriperen vet at du har oppdaget ham), men det er et eksempel på ting du kan gjøre når du kan fange opp alle autentiserte kommandoer.
Mer fleksibel kontroll: La oss si at du nettopp har oppdaget at noen har utført et XSS-angrep på nettstedet ditt.
Hvis angriperne selv har tredjeparts-JWT-ene, er alternativene dine begrensede: du må globalt deaktivere/tilbakestille OAuth/JWT-konfigurasjonen for alle tredjepartsplattformer. Dette fører til alvorlig forstyrrelse mens du prøver å finne kilden til XSS-angrepet, siden ingen kan få tilgang til noe fra disse tredjepartsplattformene. (inkludert din egen server, siden JWT-tokenene den kan ha lagret nå er ugyldige)
Hvis JWT-tokenene i stedet er beskyttet i http-only cookies, har du flere alternativer: Du kan enkelt endre serveren din for å «filtrere ut» alle lesninger/skrivinger som potensielt er farlige. I noen tilfeller er tillegg av dette «filteret» en rask og enkel prosess, som gjør at nettstedet ditt kan fortsette i «lese-only»/«begrenset» modus uten å forstyrre alt; i andre tilfeller kan ting være så komplekse at det ikke er verdt å stole på filterkoden for sikkerhet. Poenget er imidlertid at du har flere alternativer.
For eksempel, kanskje du ikke vet med sikkerhet at noen har utført et XSS-angrep, men du mistenker det. I så fall vil du kanskje ikke ugyldiggjøre JWT-tokens for alle brukere (inkludert de som serveren din bruker i bakgrunnen) bare basert på mistanken om et XSS-angrep (det avhenger av hvor sikker du er på mistanken). I stedet kan du bare "gjøre ting skrivebeskyttet en stund" mens du undersøker problemet nærmere. Hvis det viser seg at alt er i orden, kan du bare slå på bryteren igjen og gjenoppta skriving, uten at alle må logge inn på nytt og så videre.
Uansett, på grunn av disse fire fordelene har jeg bestemt meg for alltid å lagre tredjeparts JWT-er i «sikrede informasjonskapsler» i stedet for lokal lagring. Selv om tredjeparts JWT-ene for øyeblikket har veldig begrensede områder (slik at det ikke er så farlig hvis de blir stjålet), er det god fremtidssikring å gjøre dette, i tilfelle jeg ønsker at appen min skal få tilgang til mer privilegerte funksjoner i fremtiden (f.eks. tilgang til brukerens skylagring).
Merk: De fire fordelene nevnt ovenfor (for lagring av tredjeparts JWT-er i sikrede informasjonskapsler) kan også delvis gjelde for førsteparts JWT-er, hvis JWT-ene brukes som autentisering av flere backend-tjenester, og domenene/IP-adressene til disse andre serverne/tjenestene er offentlig kjent. I så fall er de "tilsvarende tredjepartsplattformer", i den forstand at "http-only cookies" hindrer XSS-angriperen i å sende direkte kommandoer til disse andre serverne, og gir noe av fordelene fra de fire punktene nevnt ovenfor. (det er ikke helt det samme, siden du i det minste kontrollerer de andre serverne, så du kan aktivere lesemodus for dem og lignende - men det vil fortsatt generelt være mer arbeid enn å gjøre de endringene på ett sted)
Svar #6
Localstorage er designet for å være tilgjengelig for JavaScript, så det gir ingen XSS-beskyttelse. Som nevnt i andre svar, finnes det en rekke mulige måter å utføre et XSS-angrep på, som localstorage ikke er beskyttet mot som standard.
På den annen side har informasjonskapsler sikkerhetsflagg som beskytter mot XSS- og CSRF-angrep. HttpOnly-flagget forhindrer at klient-side JavaScript får tilgang til informasjonskapselen, Secure-flagget tillater bare at nettleseren overfører informasjonskapselen via SSL, og SameSite-flagget sørger for at informasjonskapselen bare sendes til opprinnelsen.
Så informasjonskapsler er et mer sikkert valg for lagring av autentiseringsdata.
Svar #7
En måte å se på dette på er å vurdere risikonivået eller skadepotensialet.
Bygger du en app uten brukere, POC/MVP? Er du en oppstart som trenger å komme til markedet og teste appen raskt? Hvis ja, ville jeg sannsynligvis bare implementert den enkleste løsningen og opprettholdt fokus på å finne produkt-marked-passform. Bruk localStorage, siden det ofte er lettere å implementere.
Bygger du en versjon 2 av en app med mange daglige aktive brukere eller en app som folk/bedrifter er sterkt avhengige av? Vil et hacking-angrep bety liten eller ingen mulighet for å komme seg igjen? Hvis ja, ville jeg tatt en grundig titt på avhengighetene dine og vurdert å lagre token-informasjon i en http-only cookie.
Å bruke både localStorage og cookie/session storage har sine egne fordeler og ulemper.
Som angitt i første svar: Hvis applikasjonen din har en XSS-sårbarhet, vil ingen av dem beskytte brukeren din. Siden de fleste moderne applikasjoner har et dusin eller flere forskjellige avhengigheter, blir det stadig vanskeligere å garantere at en av applikasjonens avhengigheter ikke har XSS-sårbarheter.
Hvis applikasjonen din har en XSS-sårbarhet og en hacker har klart å utnytte den, vil hackeren kunne utføre handlinger på vegne av brukeren din. Hackeren kan utføre GET/POST-forespørsler ved å hente token fra localStorage, eller kan utføre POST-forespørsler dersom token er lagret i en http-only cookie.
Den eneste ulempen med å lagre tokenet ditt i lokal lagring er at hackeren vil kunne lese tokenet ditt.
Svar #8
Kanskje man ikke bør være altfor bekymret
Det finnes en nyttig artikkel skrevet av Dr. Philippe De Ryck som gir en innsikt i den ekte påvirkningen av sårbarheter, spesielt XSS.
Denne artikkelen er en øyeåpner!
Kort sagt, hovedbekymringen for utvikleren bør være å beskytte webapplikasjonen mot XSS og ikke bekymre seg for mye om hvilken type lagringsområde som brukes.
Dr. Phillipe anbefaler følgende 3 trinn:
Ikke vær for bekymret for hvilken type lagringsområde som skal brukes på klientsiden. Å lagre en tilgangstoken i nettleserens localStorage-område vil spare utvikleren betydelig med utviklingstid!
Gå gjennom søknaden din for eventuelle muligheter for XSS-sårbarheter. Utfør en grundig kodegjennomgang og lær hvordan du kan unngå XSS innenfor rammen av ditt malingssystem.
Bygg en forsvar-i-dybden-mekanisme mot XSS. Lær hvordan du ytterligere kan sikre applikasjonen din. For eksempel ved å bruke Content Security Policy (CSP) og HTML5-sandboxing.
Husk at når du først er sårbar for XSS, så er det game over!