Přejít k navigační liště

Zdroják » JavaScript » Několik poznámek k heslům

Několik poznámek k heslům

Články JavaScript, Různé

Přihlášení uživatele k webové aplikaci je přece tak snadné: zadá jméno a heslo, odešle a – voila! – je přihlášen. Ale co je za tím? A co by za tím mělo být? Přinesou nové technologie nějaké změny v téhle oblasti? Oprášíme staré známé technologie, nebo vzniknou nové?

„Uživatelské jméno a heslo“ patří k počítačům už od jejich dávnověku. Je to něco tak samozřejmého, že se nad tím už nikdo ani nepozastaví, a přitom to je klíčová součást bezpečnosti celé webové aplikace. Problém nastává ve chvíli, kdy se nad „jménem a heslem“ nepozastaví ani tvůrce webové aplikace. Pojďme se společně pozastavit nad samozřejmostmi a pustit trochu fantazii na špacír…

Solte!

Údaje o uživatelích bývají uloženy na serveru v nějaké databázi. Součástí údajů je uživatelské jméno, informace o hesle a další informace, podle toho, co aplikace vyžaduje. Záměrně píši „informace o hesle“ a nikoli „heslo“ – o tom, jak hloupé je ukládat hesla do databáze v otevřeném, čitelném formátu, byly napsány už spousty článků. Ve zkratce: nedělejte to; pokud to uděláte, tak se nedivte.

Mnohem lepší variantou je ukládání hesla v podobě hashe – „otisku“, který je výsledkem speciální matematické funkce. Obecně tyto funkce pracují tak, že berou vstupní data a k nim vrací řetězec, který má některé specifické vlastnosti: 1. pro stejná vstupní data je stejný, 2. má konstantní délku, 3. drobná změna vstupních dat vyvolá velkou změnu ve výsledku, 4. je prakticky nemožné nalézt různá vstupní data se stejným hashem a 5. z výsledného řetězce je v praxi nemožné rekonstruovat původní text.

Hashovacích funkcí je mnoho, ale ve webových aplikacích jsou nejpoužívanější funkce z rodiny MD (téměř výhradně MD5) a SHA (SHA1, SHA2). U MD5 byly nalezeny chyby v návrhu, které snižují jeho bezpečnost, takže mnozí tvůrci přechází na SHA algoritmy. Je na místě podotknout, že SHA1 byl rovněž označen za slabší a doporučeno je používat algoritmy SHA2 (SHA256, SHA512 atd.)

Problém bezpečnosti

Klasická situace: útočník se dostane do systému a stáhne si databázi uživatelů (příklad z poslední doby: hack hostingu banan.cz). Pokud jsou uložená hesla v čisté podobě, pak už není co řešit – útočník má databázi jmen a hesel, server je pro něj otevřený a navíc je pravděpodobné, že mnozí lidé budou mít stejné jméno a heslo i na dalších webech.

Pokud jsou hesla hashována, musí je útočník „rozlousknout“. Pravděpodobně použije tzv. „rainbow tables“ – tabulky s vypočítanými hodnotami hashů pro různé řetězce. Tyto tabulky existují pro „slovníková hesla“ i pro kombinace různých znaků o různé délce (např. „pouze malá písmena s délkou 5, 6, 7, … znaků“, „malá písmena a číslice s délkou 5, 6, …“). Pokud má uživatel „známé heslo“ nebo „krátké heslo“, je jeho nalezení v tabulkách otázkou minut.

Časově náročnější je vytvoření rainbow table podle specifikace (kterou server ochotně při registraci prozradí: „heslo musí mít alespoň 5 znaků a musí obsahovat alespoň jedno velké písmeno“). Ovšem díky možnosti pronajmout si velký výpočetní výkon v cloudu, počítat tabulky distribuovaně nebo využít CUDA není takový úkol nemožný.

Do karet hraje útočníkovi i to, že MD5, SHA1, SHA2 atd. jsou algoritmy určené pro rychlý výpočet hashe u velkých vstupních souborů. U MD5 dokáže poměrně běžný server počítat hashe rychlostí větší než 300MB za sekundu. To znamená, že např. kombinace malých písmen a číslic o délce 6 znaků může ověřit za zhruba 40 sekund (zdroj: Coda Hale, viz další text).

Jakou používáte hashovací funkci pro uživatelská hesla?

Solíme!

Čím delší heslo, tím víc času je zapotřebí na výpočet hashů možných kombinací. Tabulku pro čtyřznaková hesla si spočítáte během pár sekund, pro pětiznaková už to bude pár minut, a časová náročnost roste s délkou hesla. Ideální možností by bylo donutit uživatele, aby používali alespoň patnáctiznaková hesla se speciálními znaky, ale takový systém by jen těžko uspěl. Proto se sahá k metodě solení (salt), kdy ke „standardně dlouhým“ heslům na serveru přidáváme dlouhý řetězec. Hash je pak počítán např. pro 40 znaků – a pro tak dlouhé řetězce je vytváření rainbow tables ze všech možných kombinací téměř nemožné.

… ale zbytečně!

Pokud útočník pronikne do systému a získá přístup k databázi, je pravděpodobné, že získá i „salt řetězec“ a zjistí, jak přesně solíme. Podle této šablony si může vygenerovat nové tabulky – se znalostí „solicího řetězce“ je to opět prostá úloha, kdy místo řetězců „aaa“, „aab“, „aac“ počítáme hashe pro „supertajny-salt-aaa“, „supertajny-salt-aab“, „supertajny-salt-aac“… Počet kombinací zůstává stejný jako bez saltu a útočník má třeba během týdne dostatečnou munici na rozlomení většiny uživatelských he­sel.

Protihmatem proti tomuto postupu je variabilní salt – namísto konstantního dlouhého řetězce se používá konstantní dlouhý řetězec a k němu ještě náhodná kombinace znaků. Tu si klidně uložíme pro každého uživatele do databáze v otevřeném textu. Nezáleží na tom, že útočník bude tuhle náhodnou část znát; jde o to, že by musel pro každého uživatele budovat znovu vlastní sadu tabulek, což by bylo časově velmi náročné. (viz Joshua Thijssen: Password hashing and salting).

Jiný postup doporučuje již zmíněný Coda Hale v článku How to safely store a password. Upozorňuje na to, že hashovací algoritmy SHA a MD jsou navrženy pro rychlý výpočet otisku velkých vstupních souborů, takže i generování tabulek pro různé kombinace znaků bude rychlé. Doporučuje proto použití algoritmu bcrypt, což je adaptivní hashovací algoritmus založený na postupech ze šifrovacího algoritmu Blowfish (viz).

Bcrypt kromě hesla a salt řetězce pracuje ještě s parametrem „cost“, kterým lze ovlivnit náročnost výpočtu hashe. Můžeme tak snadno nastavit algoritmus tak, že výpočet hashe bude trvat třeba sekundu – u přihlášení uživatele ani při registraci to nepředstavuje větší problém, ovšem pro výpočet „rainbow tables“ je třeba tisícinásobně pomalejší algoritmus výrazným faktorem. Počítat tabulky týden je únosné, ovšem počítat je devatenáct let nebude asi nikdo.

Více k tématu viz: py-bcrypt, Modern password hashing, How to use bcrypt in PHP, Please use bcrypt to hash your passwords, Bcrypt implementation in JavaScript

Na časování záleží!

Když porovnáváme hash uživatelem zadaného hesla s tím, jaký je uložen v databázi, měli bychom používat „časově ekvivalentní porovnání“. Důvody popisuje již zmíněný Coda Hale v článku A lesson in timing attacks. Tyto útoky využívají faktu, že porovnávání řetězců většinou končí při nalezení první neshody, takže při dostatečně přesném měření odezvy lze zjistit, která hodnota byla vyhodnocována delší dobu a iterativně tak dojít k hodnotě celého řetězce.

Autentizace

Uživatele máme přihlášeného, co s ním dál? Asi nejčastější postup je vytvoření „session“, sezení, jehož identifikátor je uložen do cookie, a ten, kdo se touto cookie prokáže, je považován za ověřeného uživatele. Slabé místo je „session stealing“, neboli využití otevřené session útočníkem. Servery proto kontrolují např. IP adresu a při její nápadné změně sezení ukončí a uživatele odhlásí.

Pokud je v aplikaci „díra“, může útočník využít např. XSS a volat API serveru se stejnými oprávněními jako přihlášený uživatel – k dotazu jsou přidány cookies s informacemi o otevřeném sezení jaksi „automaticky“.

A co API?

Moderní webové aplikace se posouvají ze serverů na klienty – zatímco ještě před pár lety bylo naprosto přirozené, že prohlížeč sloužil jen jako zobrazovací zařízení pro „interface“, který byl kompletně generovaný a vyhodnocovaný na straně serveru, dnešní AJAXové aplikace obsahují už velkou část logiky v JavaScriptu, na straně prohlížeče, a se serverem často komunikují přes API.

V dnešních webových aplikacích je navíc stále běžnější, že HTML není jediným výstupem webového serveru. Informace bývají prezentovány čím dál častěji prostřednictvím různých API v podobě JSON či XML, a klientským programem, který se k webovému serveru připojuje, už dávno není výhradně prohlížeč. Ruku v ruce s tím jde i odklon od běžného modelu „přihlášení – probíhá sezení, udržované přes cookie a SessionID – odhlášení“, který bývá, zejména u volání API, nahrazován „per request“ autentizací, kdy klient např. „podepisuje“ každý požadavek nebo požádá o jednorázový (či krátkodobý) přístupový token, který funguje pro jeden požadavek (nebo malou sérii požadavků) a pak je zneplatněn.

Na principu podepisování požadavků funguje i HTTP autentizace, která má ale pro AJAXové aplikace jednu zásadní nevýhodu: nelze ji zatím „ovládat skriptem“. Nelze poslat požadavek a určit jméno a heslo skriptem, vždy „vyběhne“ standardní přihlašovací dialog. (Poznámka – neuvažujeme „basic“ autentizaci, která posílá jméno a heslo v otevřeném textu; o takové autentizaci ani neuvažujme jako o bezpečnostním mechanismu!)

Pokud server vrací 401 Unauthorized, zobrazí prohlížeč dialog (nebo použije uložené heslo pro dané sezení), což může být chování nežádoucí z mnoha důvodů, a tím nejprostším je třeba to, že chceme mít přihlašovací formulář jako součást stránek, v našem designu, či místo „jméno“ do dialogu napsat „mail“.

Vsuvka: znovuvynalézáme HTTP Digest

Když jsem před časem nad přihlašováním v AJAXových aplikacích přemýšlel, říkal jsem si: Vždyť přece není nutné posílat na server jméno a heslo! Obojí může zůstat uložené v prohlížeči, jméno v localstorage, heslo v sessionstorage, a vůči serveru se lze ověřit např. pomocí postupu „výzva – odezva“. Při ověřování myšlenky jsem záhy zjistil, že „vynalézám kolo“ – lépe řečeno že jsem „vynalezl“ HTTP Digest Authentication: klient poslal požadavek, server vrátil výzvu (nonce), na klientu se z nonce, jména a hesla spočítal hash a požadavek byl poslán znovu, spolu s tímto hashem.

Napsal jsem tedy implementaci HTTP Digest autentizace pro AJAXová volání v JavaScriptu, ovšem narazil jsem na výše uvedené: odpověď serveru se stavovým kódem 401 znamenala otevření dialogu prohlížeče a autentizaci „mimo možnosti JavaScriptu“. Jako dostupné řešení se nabízelo použití jiného 4XX kódu, který dialog nevyvolá. Server pak podle příznaku určil, jestli přistupuje AJAXové knihovna nebo běžný prohlížeč, a podle toho poslal buď 401 nebo „speciální 4XX“ status. Výsledek byl funkční, ale koncepčně to je poněkud na hlavu padlé – čti: hack.

Je posílání jména a hesla při loginu přírodní zákon?

Přesto by to byla možná cesta, podobná té, kterou používá např. PayPal API. Jméno a heslo neputuje po síti, zůstává na klientské straně (v prohlížeči). Můžeme ho uložit do zmíněné SessionStorage, klidně jako předvypočítaný hash, např. jako f("sessid" + f("login:password")), kde f() je hashovací funkce a sessid identifikátor sezení. Server má v databázi hodnotu f("login:password"), identifikátor sezení se nějakým způsobem dozví (pro paranoiky třeba Diffie-Hellman algoritmem) a může si tak spočítat stejný hash. Tuto hodnotu použije klient pro „podepsání“ požadavků a server pro „ověření podpisu“. Přitom podpis nemusí být jen „hash zpávy + ověřovacího řetězce“ – můžeme použít třeba šifrování AES, na klientu celý požadavek převést např. na JSON reprezentaci, zašifrovat via AES, kde klíčem bude výše zmíněný předvypočítaný hash, a na serveru opět rozšifrovat.

Nastíněný postup připomíná SSL, čímž se dostáváme k použití HTTPS. Pravděpodobně nic nezkazíte tím, když jej použijete tam, kde to je možné. Pozor ale na míchání „HTTPS“ a „non-HTTPS“ objektů na jedné stránce!

Dokonce nemusí ani žádné sezení vzniknout a klientská aplikace (klidně napsaná v HTML/JS) může přistupovat k serveru čistě přes jednorázově podepsané API požadavky (či malé série). Bude tak postavena na stejnou úroveň jako třeba aplikace ve Flexu, nativní aplikace pro mobilní platformy či jiný „neprohlížečový“ klient, což zase posílí rozdělení aplikace na klientskou a serverovou část, které je dnes mnohdy nejasné…

Na místě je ale podotknout, že díra v aplikaci (XSS) znamená okamžitě „nulovou ochranu“ – útočník může v takovém případě napadnout cokoli, od formulářů přes úložiště až po algoritmy, a celá ochrana pak bude naprosto zbytečná, i kdybychom používali silné šifry, HTTPS a solili hesla Buchtingovou solí.

Řekni jméno, nebo…!

Pojďme ještě dál – je vůbec nutné ukládat na serveru jméno a heslo? Měl by tam být nějaký „uživatelský identifikátor“, ale nemusí to být přeci vůbec tato „svatá dvojice“! Místo jména může být na serveru také klidně „bezrozměrný hash“ – kolizi jmen při registraci odhalí, jednoznačnou identifikaci umožní a jinde „jméno“ zapotřebí není, ba naopak – čím míň toho bude server o uživatelích „vědět“, tím nižší pravděpodobnost, že případné odcizení databáze uživatelů povede k jejich kompromitaci na jiných webech. Identifikátor pro uživatele navíc klidně může spočítat samotný prohlížeč ze zadaného jména.

Mnoho z těchto postupů lze nalézt v nových autentizačních metodách (bezrozměrný ID uživatele v LiveID, Diffie-Hellman algoritmus v OAuth). Mnoho inspirace lze nalézt i ve starých osvědčených metodách (Kerberos). Zkrátka – ukládání „jména a hashe hesla“ do databáze na serveru, používané často jako „možnost první volby“, nemusí být dnes jedinou použitelnou možností. Stejně tak „session“ – nové prohlížeče, které podporují WebStorages, mohou používat jiné formy autentizace, bližší postupům z API a méně náchylným např. k „odcizení session“.

Samozřejmě je vždy potřeba zvážit, zda nová technologie nepřinese nová, zatím neznámá rizika, a zda bude dostupná pro dostatečný počet uživatelů.

tl;dr

  • Nepoužívejte pro ukládání hesel prostý text
  • Nepoužívejte pro hesla jednoduché hashovací funkce (MD5, SHA1); použijte bcrypt
  • Model „přihlášení + session v cookie“ není jediným možným modelem; zkuste využít moderní techniky
  • HTTPS pomůže
  • Tomu, kdo má v aplikaci XSS, nepomůže nic!

Komentáře

Subscribe
Upozornit na
guest
44 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
KapitánRUM

Autor asi nepracuje pro SONY.

František Kučera

Ad „Poznámka – neuvažujeme ‚basic‘ autentizaci, která posílá jméno a heslo v otevřeném textu; o takové autentizaci ani neuvažujme jako o bezpečnostním mechanismu!“

Proč ne? Pokud použijeme HTTPS*, tak je „heslo v čistém tvaru“ zabalené do šifrovaného kanálu a je v bezpečí**. A nešifrovat je hazard tak jako tak a ten CRAM nám už moc nepomůže – klientský JavaScript se stahuje ze serveru, a tudíž místo něj může útočník po HTTP poslat svůj, který heslo zadané uživatelem pošle jen tak (uživatel nic nepozná, protože JS není elektronicky podepsaný, přenosový protokol nešifrujeme a všechno vypadá OK). CRAMem se sice nic nezkazí***, ale spoléhat na něj nelze.

Ad „‚jméno‘ zapotřebí není, ba naopak – čím míň toho bude server o uživatelích ‚vědět‘, tím nižší pravděpodobnost“

Souhlas – a kéž by se to tak dělalo… bohužel praxe je taková, že provozovatelé služeb se snaží z uživatelů vytáhnout co možná nejvíc údajů (ať už jde o e-maily a čísla kreditek, spotřebitelské preference, polohu…).

Ad „HTTPS pomůže“

Spíš bych řekl: HTTPS je základ. Ono v tom klientském JavaScriptu jde naprogramovat ledasco, výkon a funkcionalita jsou dnes na slušné úrovni. Ale o tom to není – pořád se točíme kolem toho, že je potřeba přenést jakési primární tajemství (otisk veřejného klíče serveru nebo alespoň certifikační autority****, která ho podepsala) nějakým bezpečným kanálem ke klientovi. Pokud tohle nezvládneme, všechno ostatní jsou vlastně jen obskurnosti…

*) což je podle mého základ, když se mají uživatelé přihlašovat, nebo se přenášejí jakékoli citlivé údaje – nešifrované HTTP by se mělo používat jen pro přenos veřejných údajů, které jsou pro všechny uživatele stejné, a kde taky moc nezáleží na integritě zpráv (tu případně můžeme zajistit pomocí kontrolních součtů, hashů, elektronických podpisů – ale zase potřebujeme nějak bezpečně přenést ty hashe nebo otisky klíčů…)

**) pokud nevěříme tomuhle, tak už rovnou můžeme zabalit veškeré placení přes PayPal, nakupování v elektronických obchodech, posílání důvěrných mailů atd. Leda pak použít vícefaktorovou­/vícekanálovou autentizaci…

***) i když někdy taky může – k přihlášení není potřeba znát původní heslo, ale stačí jeho hash (v tom tvaru, v jakém je uložen v naší DB).

****) a nemusí jít jen o HTTPS a SSL CA – platí to pro asymetrickou kryptografii obecně

Lokutus

To je základní rozdíl mezi korporátní nekorporátní sférou. V korporátní sféře je https základ, ve sféře volných služeb ne. :-)

kutilm

Pěkný článek děkuji.
Už se těším na pokračování na téma: „Model „přihlášení + session v cookie“ není jediným možným modelem; zkuste využít moderní techniky“ :)

BTW: Jinak jednoduché hashovací funkce se dají použít, ale je s tím trochu práce: http://php.vrana.cz/opakovane-hasovani.php

pepazdepa

jak jsou na tom s ukladanim hesel zname hvezdy jako ruzne cms (drupal, joomla…), ruzne frameworky atp? je nejaky, ktery k tomu pristupuje seriozne a naopak nejaky ktery si s tim nelame hlavu? :)

Jakub Vrána

phpBB3, WordPress a Drupal 7 by na tom podle vynikajícího článku na the Month of PHP Security měly být dobře.

Jan Pobořil

Drupal solí společným klíčem a pak ješťe něčím dalším unikátním pro každý účet. Jméno a heslo se ale stejně všude posílá POSTem a pokud není zapnuté HTTPS, tak to je stejně odposlechnutelné. Pro Drupal by ale neměl být problém napsat modul, který autentizaci obohatí o v článku zmíněné mechanizmy. Některé standardnější jsou hotové a dostupné ke stažení.

František Kučera

Ten CRAM modul jsem jednu dobu i používal, ale nemá to valný smysl (už jsem tu psal proč). I na stránkách toho modulu teď radí, ať lidi raději používají SSL.

Vláďa Macek

Velmi přínosný článek, díky!

seberm

Je pro fci bcrypt nejaka alternativa v PHP?

patrik.sima
shade

Normální crypt(). http://php.net/crypt

patrik.sima

Díkes. Skvělý článek, jako vždy.

turista

Ten zesložitěný=zpo­malený hash je dobrý nápad. Ale pozor. I když ověření bude trvat jen jednu vteřinu a návštěvnost se vám zvýší, může to být např. při 4000 přihlášeních za hodinu docela problém :-)

MAge

muzes dat delay treba az po 3 spatnych pokusech z jedne IP ne?

kutilm

To moc nejde, pokud mám v db uložený hash, který se musí počítat dlouho, tak ho dlouho musím ověřovat vždy. Jinak by to nebyla žádná ochrana (ochrana v kontextu článku).

kutilm

Tohle by mohli řešit ty „moderní techniky“.

Ať si ten jednovteřinový hash třeba spočítá každý sám na klientovy a tobě ho pak jen pošle. Zátěž serveru minimální a bezpečnost zůstane zachována.

František Kučera

Pak ale pozor na to, že pro přihlášení stačí uživateli/útoč­níkovi znát hash místo hesla v čistém tvaru (takže je to v určitém směru stejné jako mít v databázi nezahashovaná hesla).

Karel

A čím se to pak liší of plaintextu? Mám v databázi ten údaj, který čekám po lince. Hashování je o tom, že dostanu po lince jiný údaj než je v databázi a já pak ověřuji, zda použití hashe na to co přišlo vede na to, co je v DB. Pokud víte co je v DB, tak vám to moc nepomůže, protože musíte odhalit co na to vede. Svého času jsme dělali i takovou prasárnu, že byla naše „živá“ databáze součástí balíku zdrojových kódů, a to včetně hashovaných hesel. Nikdo to roky neprolomil. A o tom hashování právě je – i když se dostanete k databázi, stejně se nepřihlásíte, protože nevíte, co od vás server čeká.

kutilm

Ale bavíme se tu pořád o významu „zpomaleného hashe“ (viz. komentář od turista). To znamená ochrana proti případu, kdy mi někdo odcizí celou databázi uživatelů a hesel a pomocí Rainbow table se dostane k „originálnímu“ heslu. A na to je jedno zda si ten zpomalený hash počítám na serveru nebo na klientu.

Tím nepopírám význam dalších technik s kterými se to musí kombinovat (salt, https).

Jakub Vrána

Při odcizení databáze se útočník sice nedostane k původnímu heslu (takže ho třeba nemůže použít na jiných serverech), ale získá všechny informace nutné pro přihlášení do naší aplikace.

kutilm

Na to pak, ale musím přece použít další techniky. Jako že tento „zpomalený hash“ vypočtený a poslaný z klienta, na serveru proženu jednou dalším saltem a rychlím hashem (který nezatíží server) a to mám pak v db.

Ano do mého postu jsem to přímo hned nenapsal, ale celé toto vlákno řeší problém výpočtu 4000 tisíc „zpomalených hash“ za hodinu a tohle je dle mého řešení, tohoto dílčího problému. Jak jsem psal: Tím nepopírám význam dalších technik s kterými se to musí kombinovat.

Jakub Vrána

Rychlý hash na serveru navíc by tento problém řešil, to je pravda. Počítal by se totiž z dlouhého vstupu (výstupu pomalého hashe), takže by útočník nestihl vyzkoušet všechny možnosti.

FHonza

myslím že spíše nezíská. zná sice výsledek mujhash(heslo + salt), ale z toho odvodit heslo prakticky nelze (jasně že „šifrování“ algoritmem je cesta do pekel).

kutilm

Za předpokladu, že by se s tím zpomaleným hashem (počítanem na klientovy) nic jiného na serveru nedělalo, tak by ani odvozovat heslo nemusel, poslal by prostě ten hash a to by stačilo.

nikdo

Nerozumím té části o „timing attacku“:

Jednou z vlastností hashování přeci je, že malá změna na vstupu znamená velkou změnu ve výsledném zahashovaném řetězci. Takže sledovat čas potřebný k porovnání dvou hashí je, podle mě, sice zajímavá, ale veskrze neužitečná činnost. Možná snad pro útok typu „uhádnutí hesla“ by to mohlo fungovat, ale určitě ne pro iterativní získávání hodnoty hesla. Nebo mi něco uniká?

kutilm

Dá se to použít i na zahashovaná hesla, když budu vědět jak jsou hashovaná:)

kutilm

V tom odkazovaném článku je to popsané celkem pěkně. Krátce shrnuto:

Za předpokladu, že máš v db uložený hash hesla a znáš algoritmus kterým se počítá, můžeš pak na server posílat vlastní hesla a postupně sledovat jak konvertuješ ke správnému heslu.

např.:
v db je hash: CW7h

ty pošleš heslo: kdjflsk jehož hash víš, že je A000 doba porovná cca 0sec.
ty pošleš heslo: wepurow jehož hash víš, že je B000 doba porovná cca 0sec.
ty pošleš heslo: sdůkldd jehož hash víš, že je C000 doba porovná cca 1sec. OK
ty pošleš heslo: dkjsůle jehož hash víš, že je CA00 doba porovná cca 1sec.

ty pošleš heslo: důjslkj jehož hash víš, že je CW00 doba porovná cca 2sec. OK

ty pošleš heslo: opioree jehož hash víš, že je CW70 doba porovná cca 3sec. OK

No a zachvilku jsi tam:) Rozhodně lepší než zkoušet všechny kombinace.

PS: Znalost nalezení hesla k příslušnému hashy dělá třeba už zmíněná rainbow table, nebo google:)

František Kučera

Obávám se, že takhle přesně ten čas nejsi schopný měřit, když komunikuješ se vzdáleným serverem* – tohle se dá využít tak leda když trápíš nějaký HW token a můžeš ho napojit na přesné přístroje a máš ho fyzicky u sebe.

Navíc ten server může být chráněný nějakým IDS/IPS a po chvilce tě vyhodnotí jako útočníka a odřízne. Také ta aplikace bude dost možná mít nějakou ochranu – např. při každém nezdařeném pokusu o přihlášení, tam přidá nějaký ten sleep(), aby ti to nešlo tak rychle (když bude zdržení pár vteřin, tak je to pro uživatele, který nemůže trefit heslo, ještě přijatelné, ale pro útočníka už nepoužitelné).

*) mění se zatížení jeho CPU, mění se vytížení sítě, odpovědi jsou náhodně zdržované a to o mnohonásobně více, než je rozdíl při porovnání dvou (různě podobných) řetězců.

kutilm

Cituji citaci z citovaného článku:
„It’s an attack which takes some planning and analysis, but it’s viable.“
je to delší, ale tohle je důležitý závěr.

Každopádně souhlasím, že se tomuto útoku dá bránit (jako každému), jen ho musím znát a předpokládat. Zajímavé je, že přidávání konstantního sleep je v tom článku také popsáno a to pouze prodlouží čas útoku, ale nezmaří to podstatu, na kterou se útočí.

Karel

Tenhle útok se opravdu používal, ale ne při útoku na vzdálený systém. Při útoku po síti to nefunguje ze tří důvodů:
1. Latence sítě je vždy o mnoho řádů jinde než doba na kontrolu řetězce.
2. Program musí nejprve z textu spočítat hash a teprve ten kontroluje – u všech běžně používaných hashových funkcí je čas výpočtu hashe opět řádově někde úplně jinde než porovnání dvou krátkých textů.
3. Nepracujete v laboratorním prostředí – rozdíl v době doručení paketů je opět řádově jinde a na serveru poběží řada procesů, které se budou prát o zdroje a navzájem se ovlivňovat.
Uvědomte si, že u dnes běžného HW se pro případy „nesouhlasí první znak“ a „nesouhlasí dvacátý znak“ bavíme o rozdílu nejvýše v desítkách nanosekund. I s naprosto luxusním pingem 1 milisekunda a kontrolou na plain text je zřejmé, že nezměříte nic.

Jestli ten útok chcete použít, tak ten cíl dopravte co nejblíže, zajistěte laboratorní podmínky a pokuste se ho zpomalit. V HW tokenu se například vyměňovaly krystaly a kondenzátory, protože u taktu 5Hz už opravdu i něco změříte.

biggringo

No nevím:

1. Latence bude plus/minus konstantní, takže ji můžu změřit a odečíst.

2. Taktéž můžu odečíst.

3. V tom článku se píše, že i po síti je měřitelné zpoždění s přesností na mikrosekundy.

petík

v tom článku se také píše, že je potřeba provést několik tisíc měření na jedno „heslo“ pro zjištění času s dostatečnou přesností – a bylo by nutné měřit v období, kdy je nízká až nulová zátěž serveru. Obecně by pro odvrácení stačil malý náhodný sleep, možná i sleep(0).

kutilm

Rád bych sem do diskuze přidal jednu malou úvahu.
Článek krásně popisuje, jak se dají ukládat uživatelská jména a k nim příslušná hesla. Jak se to dá zabezpečit a jak se na to dá různě útočit. Napadlo mě, ale že tu nikde není zmínka o tom, že je potřeba brát také ohled na to jak důležitá data (včetně hesla samotného) chráníme. Má někdo z vás obrněné vozidlo, které mu převáží jeho peněženku? Nebo kdo má doma bankovní trezor podobný tomu co v ČNB?

Takže pokud budu navrhovat architekturu zabezpečení internetové bankovnictví, použiju jiné zabezpečení. Pokud administraci e-shopu, tak zase jiné a na moje osobní stránky, klidně nahrávám data přes ftp, kde jde heslo v plaintextu a nijak mě to nebolí.

Jeden příklad na závěr: Mám webovou admistraci fotek pro malou (tří členou) skupinu lidí. Jednou za rok tam nahraji tak 500-800 fotek a oni je třídí do adresáře A, B a C a já si to pak zas stáhnu. To je vše.
Jaké tam mám zabezpečení: http + heslo v plaintextu jako basic autentizace + tři hesla natvrdo v kódu.
A přitom si myslím, že je to dostatečné zabezpečení a nijak víc to ani zabezpečovat nepotřebuji, není totiž důvod.
Děkuji.

nikdo

Máte pravdu, ale článek je, IMHO, psán hlavně pro ty, kdo si myslí (vaším příměrem), že nosí svou peněženku v zamčeném kufříku připoutaném pouty k zápěstí, ale když se na ten kufřík podívají po přečtení blíže, zjistí, že je to jen obyčejná igelitka, navíc ještě dole děravá.

kutilm

Když jsme u těch analogií, tak já spíše tvrdím, že pokud nechám v autě na sedačce 500kč, tak ano je potřeba zamknout a zapnout alarm. Pokud v autě na sedačce nechám vlastnoručně vyrobenou 500,- (takovou jako jsou ve hrách na sazky a dostihy třeba) tak ty opravdu zamykat nebudu. Chci tím říct, že budu dělat jen takové zabezpečení u něhož náklady na jeho překonání jsou jen malinko větší, než hodnota, kterou může útočník získat pokud ho dokáže překonat.

Jinak rozdíl v nákladech na plaintext verzus hash jsou opravdu minimální. Nicméně https, o kterém píšeš „HTTPS BY MĚL BÝT základ“, by v mém příkladu byl taky overkill.

A co se týče tvé poslední poznámky: „šak co, vždyť je to jen moje stránka“.
Tak co třeba takhle: „šak co, vždyť je to jen moje stránka, přece nemá smysl k ní dělat IPS.“

kutilm

Přesně stejný příklad jsem už do komentáře napsal a nakonec jsem to smazal:), tak to zkusím zrekonstruovat.

if (md5(heslo) == „abfde472…“) je cca o třicet vteřin nákladnější, musím totiž dohledat md5 pro syslik77. Takže v tom to není. Problém je v dlouhodobé uživatelské podpoře. Pokud mi každý rok ti dva volají, kde ty fotky jsou a jaké je heslo, kouknu do zdrojáků na notebooku a hned mohu diktovat. Pokud by tam byl hash tak nevím a jediným řešením je vymyslet nové heslo (vorvaň88), dohledat md5, po editovat soubor, připojit a nahrát na server.
Další rok nový telefonát, že v souboru hesla.txt co mají na ploše, mají napsáno heslo syslik77 a že se tam nemohou dostat, co tím?

Teď přemýšlím jestli bych to nemohl dát rovnou bez hesla na adresu http://www.example.com/tajny-adresar-8e7R/ a bylo by :)

Jinak se omlouvám pokud jsi si vyložil tu větu o nahrávání dat na osobní stránky přes ftp, jako že tím nějak pohrdám, nikoliv. Chtěl jsem tím jen říct, že na každý projekt je nutné se dívat individuálně a vybírat tomu ekvivalentní nástroje.

Jiří Kosek

Kdyby tak všichni používali editor, který umí spočítat md5 ;-)

kutilm

Promiň ještě jsem zapomněl: „Otázka je, jak přesně odhadnu hodnotu toho, co útočník může získat..“

To není jednoduché ano, ale řádově to stejně vždy musí někdo udělat. Třeba podvědomě a neplánovaně, a ekvivalentně tomu investuje do ochrany.

Každý soudný jednotlivec, který uploaduje fotky na picasa, tak umí odhadnout zda fotky budou veřejné, nebo pod heslem. Ten kdo má osobní stránky, tak podvědomě vybírá hosting zadarmo a cítí, že to nebude takové jako hosting za 500/měsíčně.
Každý majitel prosperujícího eshopu je schopen odhadnout, jak citlivé by byli informace o objednávkách pro konkurenci a podle toho zaměstná studenta, nebo firmu. Kamkoliv víš nad eshop je to ještě jednodušší, tam už jsou si manažeři vědomi citlivosti svých dat.

A ano ne vždy se to povede, ale o tom je život, SONY taky přišlo o data.

PS: možná bychom tu diskuzi mohli ukončit, věřím že si na 99% rozumíme a kvůli tomu jednomu procentu je škoda plevelit diskuzi. Každopádně děkuji.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.