Späť na blog
28. júla 2026

Naša vlastná aplikácia ukladala auth tokeny do localStorage. Čo sme s tým urobili.

Viktor Bulanek
Founder & CTO, Penetrify
MSc IT Security · 20+ years in security · 4x Ex-CTO

V júni sme Penetrify pustili na našu vlastnú aplikáciu, ako to robíme pred väčším releasom. Scan sa vrátil s problémom v našom prihlasovaní cez Cognito, a keď som za tú nitku zatiahol, vyšlo z toho niečo, čo som nečítal rád: dashboard Penetrify držal access a refresh tokeny z Cognita v localStorage, v plaintexte, čitateľné akýmkoľvek JavaScriptom na stránke.

Nesadli sme si a takto sme sa nerozhodli. Je to default auth knižnice, ktorú sme použili, a nikdy sme ho nespochybnili. Práve to je na tom to zaujímavé.

Čo presne bol ten nález

Náš dashboard je single-page aplikácia. Po prihlásení dostala tokeny z AWS Cognita a SDK ich uložilo do browser storage, pretože tam ich SDK ukladajú, keď v session nie je zapojený server. Prečítať ich mohol akýkoľvek skript s prístupom na stránku.

Znamená to, že jedna cross-site scripting chyba kdekoľvek v aplikácii, jedno škodlivé rozšírenie prehliadača alebo jedna kompromitovaná npm závislosť, a útočník odchádza s oboma tokenmi. Access token ho dostane do účtu. Refresh token ho tam udrží, pretože zostáva platný dlho po tom, ako session vyzerá zatvorená, kým ho niečo výslovne nezneplatní.

U našich užívateľov boli v dosahu fakturačné údaje, výsledky scanov ich aplikácií a dáta o affiliate výplatách. Nakoľko to vieme posúdiť, nikto to nezneužil. O to však nejde. Bolo to dosiahnuteľné a bol to náš vlastný default na opravu.

Prečo šifrovanie localStorage nie je riešenie

Prvý instinkt je tokeny pred uložením zašifrovať. Nepomôže to. Dešifrovací kľúč musí žiť v tom istom JavaScripte, ktorý útočník už spúšťa. Pridal si krok, nie hranicu.

Druhý instinkt je presunúť tokeny do cookie na strane klienta. To tiež nepomôže. Cookie nastavená JavaScriptom je JavaScriptom čitateľná. Vlastnosť, na ktorej záleží, je HttpOnly, a nastaviť ju dokáže len server, hlavičkou Set-Cookie. Ak tvoja oprava beží v prehliadači, nie je to oprava.

Čo sme nasadili namiesto toho

Celú session sme presunuli do cookies nastavovaných serverom, vzorom token handler vnútri backendu, ktorý sme už mali:

  • FastAPI backend vykonáva volania na Cognito a vracia session ako cookies s HttpOnly, Secure a SameSite. Prehliadač token nikdy nevidí.
  • Auth middleware číta access token z cookie namiesto hlavičky Authorization.
  • Pretože sa cookies posielajú automaticky, mutujúce requesty teraz nesú CSRF token v hlavičke, ktorý backend overuje.
  • Odhlásenie vykoná global sign-out na strane Cognita, takže token, ktorý niekedy unikol, umrie so session namiesto toho, aby ju prežil.
  • Auth SDK je z prehliadača úplne von.

Nepotrebovali sme na to novú službu. Naša statická aplikácia a naše API sú už teraz na tom istom origine: CloudFront servíruje aplikáciu a route /api/* posiela na API Gateway. First-party cookie sa tak posiela s každým volaním API bez akejkoľvek ďalšej infrastruktúry.

Najprv sme sa pozerali na cestu odporúčanú vendorom, čo by znamenalo prevziať hostované prihlasovacie UI, a zamietli sme ju. Zahodila by naše vlastné obrazovky pre login, MFA a reset hesla kvôli problému, ktorý dokážeme vyriešiť v existujúcom backende.

Čo to stálo

Asi týždeň práce a žiadnu viditeľnú zmenu pre užívateľov. To je úprimný súhrn väčšiny bezpečnostnej práce a presne preto sa takéto veci v startupe odkladajú do nekonečna. Na roadmape sa nič nepohne. Žiadny zákazník o to nepožiada. Zmení sa len to, čo s tvojimi užívateľmi dokáže urobiť jediný injektovaný skript.

Jeden praktický detail, ktorý nasadenie zbezpečnil: počas rolloutu backend stále prijímal starú cestu cez hlavičku, takže revert frontend deployu bol rollback na jeden krok, keby sa čokoľvek pokazilo.

Over si vlastnú aplikáciu. Zaberie to asi 30 sekúnd.

Otvor svoju aplikáciu, prihlás sa a otvor DevTools:

  • Záložka Application, Local Storage. Hľadaj dlhé hodnoty s dvoma bodkami. Tento tvar je JWT.
  • V tom istom paneli skontroluj Session Storage. Rovnaký problém, kratšia životnosť.
  • V konzole napíš document.cookie. Čokoľvek sa tam objaví, je z definície čitateľné JavaScriptom, takže session cookie, ktorú v tom výpise vidíš, ťa nechráni.

Ak token nájdeš, je to nález. Nie teoretický, a nie taký, na ktorý by ťa upozornil zelený audit závislostí alebo čistý beh statickej analýzy.

Prečo to publikujeme

Dva dôvody, a ten druhý je o našom vlastnom produkte.

Prvý: defaulty sú rozhodnutia, ktoré za teba urobil niekto iný. Prídu s knižnicou, sú pohodlné a takmer nikdy nie sú threat model. Ten náš bol rozumný default pre tutoriál a zlý pre aplikáciu, ktorá drží platobné dáta.

Druhý: scan je ukazovateľ, nie verdikt. Ten náš označil prihlasovacie flow a dokázal, že je dosiahnuteľné. Nepodal nám vetu „tvoja auth knižnica má default localStorage a práve to treba zmeniť". Cesta od nálezu k oprave znamenala otvoriť si vlastnú auth cestu a prečítať ju. Presne tak očakávame, že budeš používať aj naše reporty: nález ti povie, kam sa pozrieť, a ukáže request, ktorý to dokazuje, a ty sa potom rozhodneš, čo je správna oprava v tvojej architektúre.

Takže: pusť scan na vlastnú aplikáciu a potom si prečítaj kód, na ktorý ukazuje. Urobili sme oboje a ani jedna polovica by sama nestačila.

Ak chceš pohľad na svoju aplikáciu zvonku hneď teraz, náš bezplatný security check zaberie asi 60 sekúnd a nechce registráciu. Ak chceš plný report s dôkazmi a opravami, prvý scan je za $29 a započíta sa do plánu. A ak chceš radšej tú vec zadarmo, ktorú sme opísali vyššie, otvor DevTools a pozri sa do svojho local storage. Tá nestojí nič.

Frequently Asked Questions

Aké typy zraniteľností Penetrify detekuje?

Penetrify detekuje všetky kategórie zraniteľností OWASP Top 10 vrátane SQL injection, XSS, CSRF, IDOR, nefunkčnej autentifikácie, bezpečnostných miskonfigurácií a úniku citlivých dát. Testuje tiež bezpečnosť API, správu relácií a bežné miskonfigurácie v Supabase, Firebase a Bubble.

Ako dlho trvá AI penetračný test?

Rýchle skenovanie je dokončené za 15–30 minút. Štandardné skenovanie trvá 1–2 hodiny s širším pokrytím. Hĺbkové skenovanie môže trvať niekoľko hodín pre zložité aplikácie.

Čo obsahuje správa Penetrify?

Každá správa obsahuje executive summary, celkové bezpečnostné skóre, nálezy klasifikované podľa závažnosti (Kritické, Vysoké, Stredné, Nízke), podrobné kroky pre reprodukciu a konkrétne odporúčania pre nápravu napísané pre vývojárov – nie pre špecialistov na súlad.

Related articles

Alternatívy DAST v roku 2026: Keď dynamické skenovanie nestačí (a čo použiť namiesto toho)
DAST skenery prehliadajú autentifikačné toky, biznis logiku a moderné API. Prinášame úprimné porovnanie DAST oproti SAST, IAST, PTaaS a autonómneho Penetration Testingu poháňaného AI – a kedy použiť ktorý.
What an autonomous pentest agent found in 3,847 apps — and what your scanner didn't
A data breakdown of 47,291 exploitation-validated findings, with methodology and limitations. 91% of the SQL injection we found shipped despite a SAST gate in CI; 78% of critical findings needed no login.
Indirect Prompt Injection to Data Exfiltration: When the Model Has Tools
Prompt injection on its own is a curiosity. Prompt injection reaching a tool that holds real credentials is a breach — and the instruction does not have to come from your user. It can arrive inside the document your app was asked to summarise.

Explore more