Penetrační testování webových aplikací: 5 zranitelností, které najdeme nejčastěji

·

·

Adam Tretera

Většina webových aplikací vypadá zvenčí bezpečně. Přihlášení funguje, HTTPS svítí zeleně, data se ukládají tam, kam mají. Přesto v devíti z deseti aplikací, které testujeme, najdeme kritickou nebo vysoce závažnou chybu. A nebavíme se o amatérských projektech — jde o aplikace od profesionálních dodavatelů, které roky běží v produkci.

Tohle je pět zranitelností, na které narážíme nejčastěji, proč vznikají a co s nimi.

Co penetrační test vlastně dělá

Penetrační test není bezpečnostní sken. Automatický scanner projde známé signatury a vygeneruje report o dvou stech stranách, ve kterém je většina nálezů šum. Penetrační test znamená, že se člověk pokusí do aplikace skutečně dostat — stejnými postupy jako útočník, ale s vaším svolením a s dokumentací každého kroku.

Rozdíl je vidět na výsledku. Scanner odhalí zastaralou knihovnu. Tester odhalí, že si běžný uživatel může změnou jednoho čísla v URL zobrazit faktury cizí firmy.

1. SQL injection

Klasika, která nezemřela. Vzniká, když se vstup od uživatele skládá přímo do databázového dotazu. Útočník pak místo jména napíše něco, co databáze vyhodnotí jako příkaz — a dotaz začne dělat něco jiného, než měl.

Následky jsou obvykle ty nejtěžší z celého seznamu: přečtení celé databáze včetně hesel, jejich změna, nebo smazání. Nejčastěji to vidíme ve starším kódu, v reportech a exportech, které si někdo psal „narychlo", a v místech, kde se filtrování skládá dynamicky podle parametrů z URL.

Řešení: parametrizované dotazy nebo ORM, důsledně a bez výjimek. Žádné skládání SQL spojováním řetězců — ani „jen na tomhle jednom místě, kde je to interní".

2. Cross-site scripting (XSS)

Aplikace zobrazí text od uživatele bez ošetření a prohlížeč ho vyhodnotí jako kód. Útočník tak spustí vlastní skript v prohlížeči někoho jiného — typicky aby mu ukradl session a přihlásil se jako on.

Nejčastější místa nálezu jsou podle naší zkušenosti tahle:

  • Komentáře, poznámky a interní chaty

  • Jména a názvy, které se vypisují v administraci

  • Nahrané soubory a jejich názvy

  • Chybové hlášky, které vracejí zpět to, co uživatel zadal

Řešení: escapovat na výstupu, nastavit Content-Security-Policy a vyhnout se přímému vkládání HTML (innerHTML, dangerouslySetInnerHTML). Pokud uživatelé musí mít formátovaný text, projet ho osvědčenou sanitizační knihovnou — ne vlastním regulárním výrazem.

3. Slabá autentizace a správa hesel

Tady většinou nejde o jednu chybu, ale o sadu drobností, které dohromady stačí. Co vídáme nejčastěji:

  • Přihlašování bez jakéhokoli omezení počtu pokusů

  • Hesla uložená slabým algoritmem, nebo dokonce v čitelné podobě

  • Session, která nevyprší a zůstane platná i po odhlášení

  • Reset hesla s tokenem, který se dá uhodnout nebo nemá expiraci

  • Testovací a servisní účty, na které se po nasazení zapomnělo

Řešení: rate limiting na přihlášení, moderní hashovací funkce (bcrypt, argon2), dvoufaktorové ověření alespoň pro administrátory a pravidelná revize účtů. Servisní účty patří do inventáře, ne do poznámek.

4. CSRF

Útok, při kterém přihlášený uživatel nevědomky odešle požadavek, který nechtěl. Stačí, aby byl přihlášený ve vaší aplikaci a otevřel cizí stránku — ta na pozadí odešle požadavek jeho jménem. Aplikace ho přijme, protože přijde s platnou session.

Rizikové jsou hlavně akce, které něco mění: změna e-mailu, přidání uživatele, potvrzení platby. U moderních frameworků bývá ochrana zapnutá ve výchozím stavu — a právě proto ji občas někdo vypne, když „něco nefungovalo", a už se to nevrátí zpět.

Řešení: CSRF tokeny u všech stavových požadavků a atribut SameSite u cookies. A hlavně ověřit, že ochrana je opravdu aktivní i v produkci, ne jen v konfiguraci.

5. Nezabezpečené API

Nejčastější nález posledních let. Frontend správně skryje tlačítko „Smazat uživatele" všem kromě administrátorů. Endpoint za ním ale nekontroluje nic — a zavolat ho může kdokoli.

Do stejné kategorie patří i situace, kdy endpoint vrátí víc dat, než má. Detail objednávky obsahuje celý objekt zákazníka včetně telefonu a adresy, i když se na stránce zobrazí jen jméno. Data přitom odejdou na klienta a stačí se podívat do vývojářské konzole.

Řešení: autorizaci řešit na serveru u každého endpointu zvlášť, nikdy ne skrýváním prvků v rozhraní. Odpovědi omezit jen na pole, která se opravdu používají. A u každého identifikátoru v požadavku ověřit, že na něj má přihlášený uživatel právo.

Diagram

Jak test probíhá

U nás má penetrační test čtyři fáze a u běžné aplikace trvá jeden až dva týdny:

  • Sběr informací — zmapujeme, z čeho se aplikace skládá, jaké má vstupy a role

  • Testování — kombinace automatizovaných nástrojů a ruční práce, kde je největší přínos

  • Ověření dopadu — u každého nálezu doložíme, co konkrétně umožňuje, ne jen že „existuje riziko"

  • Report a retest — nálezy seřazené podle závažnosti, s konkrétním postupem opravy a následnou kontrolou

Report bez retestu považujeme za nedodělanou práci. Teprve ověření, že oprava skutečně zabrala, uzavírá nález.

Kdy má smysl testovat

Ideálně před spuštěním do produkce a pak jednou ročně. Mimo tento rytmus se vyplatí test po každé větší změně — nová platební brána, otevření veřejného API, migrace na jinou infrastrukturu nebo převzetí aplikace od předchozího dodavatele.

Poslední bod podceňují firmy nejčastěji. Když přebíráte kód, přebíráte i všechny chyby, o kterých nevíte — a odpovědnost za ně je od té chvíle vaše.

Řešíte bezpečnost své aplikace, nebo přebíráte projekt po jiném dodavateli? Ve Softero děláme penetrační testy a bezpečnostní audity webových aplikací — ozvěte se nám a probereme, co dává ve vašem případě smysl.