Bezpečnostní díry, které jsme opravovali po ostatních

Když přebíráte cizí projekt, je to trochu jako stěhovat se do bytu po předchozím nájemníkovi. Na první pohled vypadá všechno v pořádku. Pak otevřete skříň a zjistíte, že za ní chybí kus zdi. A za tou zdí žijí věci, o kterých nechcete vědět.
Za roky praxe jsme převzali desítky projektů od jiných dodavatelů. Některé byly v rozumném stavu. Některé byly katastrofa. A pak tu byla speciální kategorie -- projekty, kde nás bezpečnostní audit probudil uprostřed noci studeným potem.
Tady je pár příběhů. Jména a detaily jsou samozřejmě změněné, ale technické problémy jsou bohužel naprosto reálné.
"Autorizaci jsme zakomentovali pro testování"
Převzali jsme e-commerce platformu středně velkého klienta. Všechno vypadalo na první pohled funkčně -- hezký frontend, fungující košík, platby chodily. Pak jsme otevřeli administrační panel.
Přesněji řečeno: otevřel ho kdokoli. Stačilo zadat URL adminu a byli jste uvnitř. Žádné přihlášení, žádná kontrola oprávnění.
V kódu jsme našli middleware pro ověření přihlášení. Byl tam. Pečlivě napsaný. A celý zakomentovaný. Nad ním svítil komentář: // TODO: uncomment after testing. Ten komentář tam byl osm měsíců. Osm měsíců mohl kdokoli, kdo znal nebo uhodl URL adminu, přistupovat k objednávkám, zákaznickým údajům, cenám -- ke všemu.
Nejhorší na tom? Klient o administračním panelu věděl a aktivně ho používal. Nikdy ho nenapadlo, že to, že se nemusí přihlašovat, je problém. "Prostě to fungovalo," řekl nám.
API, které vracelo úplně všechno
Další projekt, mobilní aplikace s REST API. Klient si stěžoval na pomalost, tak jsme se podívali na backend. Endpoint pro vyhledávání uživatelů přijímal parametr query. Když jste poslali normální dotaz, dostal jste rozumné výsledky.
Když jste poslali prázdný string? API vrátilo kompletní dump všech uživatelů v databázi. Včetně e-mailů, telefonních čísel, adres. A ano -- včetně hashovaných hesel. A ano, ty hashe byly MD5 bez soli.
Pro ty, kdo nejsou v bezpečnosti doma: MD5 hashe bez soli se dají prolomit za minuty pomocí rainbow tables. V podstatě to bylo totéž, jako kdyby tam hesla byla v čitelné podobě.
Zajímavost? Ten endpoint volala i veřejná registrační stránka pro kontrolu, zda uživatelské jméno už existuje. Takže každý, kdo otevřel vývojářské nástroje v prohlížeči, mohl bez jakéhokoli přihlášení stáhnout celou uživatelskou databázi.
Platební brána jako otevřená kniha
E-shop s vlastním napojením na platební bránu. Klient měl problém s reklamacemi a chtěl, abychom se podívali na historii transakcí. Když jsme otevřeli logy, zbledli jsme.
Aplikace logovala kompletní požadavky a odpovědi platební brány. Včetně plných čísel kreditních karet. Včetně CVV kódů. Včetně jmen držitelů. Všechno v plain textu, v logovacích souborech, které byly -- samozřejmě -- dostupné přes web, protože je nikdo nepřesunul mimo veřejný adresář.
Tohle není jen bezpečnostní díra. Tohle je porušení PCI DSS standardu, za které hrozí pokuty v řádu milionů. A kdyby se to dostalo k regulátorovi, klient by přišel o možnost přijímat karetní platby.
Opravu jsme řešili jako krizovou situaci. Logy okamžitě smazat, endpoint zabezpečit, nasadit tokenizaci. A pak dlouhý, nepříjemný rozhovor s klientem o tom, co se stalo a co to znamená.
JWT secret: "secret123"
Webová aplikace s JWT autentizací. Vypadalo to moderně a čistě. Přihlášení, tokeny, refresh tokeny -- vše podle učebnice. Až na jeden detail.
JWT secret -- klíč, kterým se podepisují všechny autentizační tokeny -- byl nastaven na secret123. Doslova. Nebylo to v testovacím prostředí. Bylo to v produkci. Osmnáct měsíců.
S tímhle secretem si mohl kdokoli vyrobit vlastní platný JWT token. S libovolným user ID. S libovolnou rolí. Včetně administrátora. Stačilo nainstalovat jwt.io, zadat secret a vygenerovat si vlastní token. Celý autentizační systém byl v podstatě divadlo.
Když jsme se zeptali předchozího dodavatele (klient nás propojil), odpověď byla: "Jo, to jsme chtěli změnit, ale pak jsme na to zapomněli."
Uživatelské role v cookie
Systém pro správu firemních dokumentů. Měl tři role: čtenář, editor, admin. Logicky byste čekali, že role je uložená v databázi a kontroluje se na serveru.
Místo toho byla uložená v cookie. V nešifrované, nepodepsané cookie. Doslova role=reader. Změna na role=admin v prohlížeči vyžadovala přesně pět sekund a nulové technické znalosti.
Přidejme k tomu, že v systému byly uloženy smlouvy, finanční výkazy a personální dokumenty. Každý zaměstnanec s přístupem čtenáře mohl editovat nebo mazat cokoli. Stačilo upravit jednu cookie.
Nahrajte si, co chcete
Content management systém s možností nahrávání souborů. Obrázky, dokumenty, přílohy. Standardní funkce. Nestandardní byla implementace: žádná validace nahrávaných souborů. Vůbec žádná.
Formát? Nekontroluje se. Velikost? Nekontroluje se. Název? Nekontroluje se. Kam se soubor uloží? Do veřejného adresáře, přímo spustitelného serverem.
To znamená, že kdokoli mohl nahrát PHP soubor, přistoupit k němu přes URL a spustit libovolný kód na serveru. V bezpečnostním žargonu se tomu říká Remote Code Execution a je to přibližně nejhorší věc, která se může stát.
Když jsme to klientovi oznámili, odpověděl: "Ale vždyť ten formulář pro nahrávání je schovaný, nikdo o něm neví." Bezpečnost skrýváním. Klasika.
Co nás to naučilo
Každý z těchto příběhů má jednoho společného jmenovatele: bezpečnost nebyla prioritou. Byla to ta věc, která se "dodělá později", "dořeší v další verzi", "zatím to stačí".
Bezpečnost se ale nedodělává. Buď je součástí vývoje od začátku, nebo tam není.
Několik praktických ponaučení:
Bezpečnostní audit není luxus, ale základní součást každého projektu. Nezáleží na tom, jak malá je aplikace nebo jak málo uživatelů má. Jeden neošetřený endpoint může způsobit škody za miliony.
Testovací konfigurace nesmí nikdy zůstat v produkci. Zakomentovaná autorizace, výchozí hesla, debug módy -- tohle všechno musí být součástí deployment checklistu.
Nikdy nedůvěřujte klientovi. V bezpečnostním smyslu -- nikdy neukládejte citlivá data tam, kde k nim může klient (prohlížeč, cookie, URL) přistupovat a manipulovat s nimi.
Logujte, ale s rozumem. Logy jsou nezbytné pro debugging. Citlivá data v nich nemají co dělat. Nikdy. Za žádných okolností.
A pokud přebíráte projekt od jiného dodavatele? Bezpečnostní audit jako první krok. Ne druhý, ne "až bude čas". První. Protože ten zakomentovaný auth middleware už tam možná čeká osm měsíců.
Přebíráte cizí kód? Začněte tímto checklistem: 1) Zkontrolujte autentizaci a autorizaci — jsou aktivní a na serveru? 2) Hledejte citlivá data v logách, cookies a API odpovědích. 3) Ověřte, že JWT secret není výchozí hodnota. 4) Zkontrolujte upload endpointy — validují typ a velikost souborů? 5) Spusťte OWASP ZAP scan na celou aplikaci.


