Podívejte se raději na online verzi přednášky, slajdy mohly být aktualizovány nebo doplněny.

Detail přednášky

Na webové vývojářské konferenci Devel.cz, která se konala v prostorách Fakulty informačních technologií ČVUT v pražských Dejvicích, jsem měl přednášku o správném ukládání uživatelských hesel do databáze.

Upoutávka na přednášku zněla takto: Ukládáš hesla do databáze jen tak, v čitelné podobě? Nebo používáš MD5? Nebo snad SHA-1? Vsadím se, že nevíš, co je to salt. Taky tajně doufám, že neposíláš hesla e-mailem. Jednoho krásného dne se někde na webu objeví obsah databáze tvojí webové aplikace a její uživatelé nebudou mít radost. Nevystavuj je zbytečnému nebezpečí a raději si rezervuj místo v první řadě a já ti ukážu, jak se se svým webem nedostat do hlavního zpravodajství TV Nova.

Pokud byste potřebovali změnit ukládání hesel například z SHA-1 na zmiňovaný bcrypt, podívejte se, jak jsme to udělali ve Slevomatu a přečtěte si detailnější návod.

Zajímá vás ukládání hesel? Přijďte si o tom popovídat na školení Bezpečnost PHP aplikací (nejbližší termín: termín zatím nevypsán).

Příklad na hashování hesel a následné šifrování hashů (ne hesel!) najdete u mě na Githubu.

Datum a akce

2. března 2013, Devel.cz Konference 2013 (délka přednášky 25 minut, 34 slajdů, video)

Slajdy

Zahashovat heslo, uložit, ..., profit!

#1 Takhle nějak by mohl vypadat známý tříkrokový plán, kdyby se upravil na ukládání hesel.

323 loginů + SHA-1 hashů hesel → crackstation.net

#2 Proč je vůbec ukládání hesel tak důležité? Ukážeme si příklad z naší kotliny – na jednom malém e-shopu, který jsem zmiňoval na WebTop100 2012, se dal volně stáhnout soubor se zálohou databáze, ve které bylo přes 300 uživatelských jmen a hesel zahashovaných pomocí SHA-1.

crackstation.net → 111 cracknutých hesel

#3 Řeknete si, lidský faktor, taková věc nemá být volně ke stažení. Ne, nemá, ale byla. Hashovaná hesla jsem předhodil online nástroji CrackStation, který ve svém obrovském slovníku našel 111 shod, během chvíle jsem tak získal 111 uživatelských účtů i s hesly. Útok hrubou silou by počet jistě zvýšil.

exoddus, Tbvfs1, 9plams, P1ll3d, Neznašov

#4 Zde jsou některá zajímavá hesla, která CrackStation dokázal najít ve svém slovníku. Kromě typicky českých slov jsou to i hesla, která splní podmínky pro tvorbu hesel velké části služeb a aplikací. Všimněte si hesla P1ll3d: obsahuje více než 6 znaků, malá i velká písmena a čísla.

111 cracknutých hesel → 52 k loginu …@seznam.cz

#5 Z těch 111 cracknutých a tedy čitelných hesel jich 52 patřilo k účtům, které měly e-mailovou schránku na doméně seznam.cz. Celkem takových uživatelů daného e-shopu s e-mailem na seznam.cz bylo 165, ale jen k 52 takovým účtům jsem znal heslo. Ale to mi stačilo.

52 loginů …@seznam.cz → Kolik stejných hesel jako na Seznam?

#6 Chtěl jsem zjistit, jestli vůbec a jak moc se recyklují hesla. Je třeba vzít v potaz, že vzorek dat byl malý, byl půl roku starý a také to, že firmě provozující daný e-shop jsem doporučil informovat zákazníky a doporučit jim změnu hesla. Výsledné číslo tedy ve skutečnosti může být vyšší.

9

#7 I přesto je výsledek zarážející. Z 52 hesel, která jsem měl k dispozici, jich 9 fungovalo pro přihlášení k e-mailové schránce na seznam.cz. 9 uživatelů tedy mělo a má stejné heslo pro přístup ke své e-mailové schránce, jako heslo pro přihlášení k onomu e-shopíku. Přístup ke schránce je průser, už třeba jenom proto, že v ní lze nalézt registrační údaje k dalším službám (které si nikdo nikdy nezmění, pokud mu je vygenerujete a při registraci pošlete) a také třeba proto, že weby běžně e-mailem posílají zapomenutá hesla a instrukce k nastavení nového hesla.

…@email.cz 2 z 8, …@centrum.cz 3 z 9, …@gmail.com 1 z 15

#8 Přístup k 9 schránkám na seznam.cz není všechno. Z celkem 8 účtů s adresou na email.cz používalo stejné heslo jen pár uživatelů. Získat přístup k tomu jednomu účtu na Gmailu byl trochu oříšek, Gmail totiž detekoval, že se hlásím z divného umístění (přes anonymizér) a tak chtěl po mě potvrdit, že jsem to opravdu já, kdo se k účtu snaží přihlásit. No, kdo jiný než já by to asi tak byl, že. Chtěl po mě tedy telefonní číslo toho uživatele Gmailu, ale to nebylo problém najít, jak jinak než zadáním té e-mailové adresy do … wait for it … do Google. To je ochrana k ničemu.

E-mail: [...], Heslo: [...]

#9 Domnívám se, že důvodem, proč uživatelé recyklují hesla může být částečně i to, že je k tomu webové aplikace navádějí. Pokud v jednom políčku uživatel zadává svůj e-mail, tak je možné, že do druhého políčka prostě napíše heslo k té schránce, aniž by nad tím nějak přemýšlel. Podívejte se na tento formulář ještě jednou. Trochu to dává smysl, ne? Zkuste tedy políčko pro zadání hesla doplnit například textem „nezadávejte heslo k vaší e-mailové schránce“. Třeba to uživateli dojde.

(•‿•) (•︵•) (•‿•) (•︵•)

#10 Vidíte, že pokud se hesla rozhodnete ukládat špatně, tak ohrožujete svoje uživatele. Útočník tak nepřímo může získat přístup ke službám, ke kterým by jinak jména a hesla získával dost těžko. Můj skromný odhad je, že hesla špatně ukládá půlka z vás. Vy samozřejmě ne, jen Vaše druhé já.

V čitelné podobě (v plaintextu)

#11 Co to vlastně znamená, to „ukládat hesla špatně“? Nejjednodušším špatným způsobem uložení hesla je ho uložit tak, jak do aplikace přišlo z prohlížeče, nedělat s ním žádné cviky, žádné hashování, to je sprosté slovo. Naše aplikace je přece zabezpečená, ne?

(+_+)

#12 Pokud hesla uživatelů ukládáte do databáze jen tak, tak vaši aplikaci brzy navštíví tady ten pán na obrázku. Nikdy neukládejte hesla do databáze jen tak, v čitelné podobě! Pokud se někdo nějak dostane k databázi nebo k zálohám databáze, data vašich uživatelů jsou v ohrožení.

MD5(heslo), SHA-1(heslo), CRC32(heslo)

#13 Možná jste slyšeli, že hesla se mají ukládat zahashovaná. Tedy že se mají nejdříve prohnat nějakou hashovací funkcí. To je správně, ale není to úplně správně. Jsou hashe lepší a horší. A i ty dobré se dají použít špatně. Uvedené hashe nejsou nejlepší a navíc jsou špatně použité.

Obama: NOPE

#14 Funkce MD5, SHA-1 a CRC32 jsou dobré na kontrolu integrity dat, ale ne na hashování hesel uvedeným způsobem. V příkladu na začátku jste viděli, že hesla byla hashována pomocí SHA-1, ale ničemu to nepomohlo, původní hesla nebyl problém získat. Takhle tedy také ne.

Google 54bd33f9fdb722bb03d6bbba1537d3f9

#15 Existují totiž databáze předpočítaných MD5 a SHA-1 hashů pro různé možné i nemožné řetězce. Pokud do výpočtu hashe nepřidáte salt, viz dále, tak velkou část hesel lze v těchto databázích najít. Umí v nich hledat i Google, nalezení původního hesla je často otázka jednoho dotazu.

Radeon+Radeon+Radeon+Radeon+Radeon+Radeon+Radeon+Radeon

#16 Pokud databáze předpočítaných hashů nestačí, tak třeba pomůže grafická karta a software, který na ní umí lámat hashe. Jeremi Gosney postavil cluster s celkem 25 GPU, který umí vytvořit třeba 180 miliard MD5 hashů za vteřinu. Hrubá síla FTW. A ano, to nahoře je počítač.

R7990 × 16

#17 Jak jde čas, tak si Jeremi kupuje pořád nějaké nové nejvýkonnější grafické karty. Žádná z nich sice nikdy nezobrazí ani jeden pixel, ale crackování hesel na nich sviští od rána… do rána. Tohle je fotka z roku 2013, nějakou dobu před vánoci.

Sagitta HPC (High Performance Cracking)

#18 V roce 2015 Jeremi Gosney staví cluster s 96 GPU a do konce 2016 v něm chce mít 192 GPU. Pokud hesla ukládáte jako MD5 nebo SHA-1, tak je to stejné, jako kdyby byla v plaintextu. Jeremi takové stroje prodává, server s 8 GPU stojí $18499, ale na StarCraft si kupte něco levnějšího.

MD5(MD5(MD5(MD5(MD5(MD5(MD5(MD5(MD5(MD5(MD5(MD5(MD5(MD5(heslo))))))))))))))

#19 Algoritmy MD5 a SHA-1 jsou velice rychlé, což pomáhá nejen při útoku hrubou silou. To ale pro bezpečné ukládání hesel není moc dobrá zpráva. Dobu nutnou pro výpočet hashe z hesla můžeme prodloužit vícenásobným voláním daných funkcí, ale nikdy ne takto jednoduše.

HA HA HA NO

#20 Počet opakování musí být celkem vysoký (v tisících), navíc velmi záleží na použitém algoritmu, při vícenásobném hashování pomocí MD5 vzniká větší počet kolizních součtů napadnutelných útokem vedeným nějakým tunelem. Nebo tak něco. Tudy raději tedy ne, tunelů máme už tak dost.

v@_

#21 Z doposud uvedeného tedy plyne, že potřebujeme nějakou pomalou hashovací funkci. Relativně pomalou, tedy takovou, aby výpočet jednoho hashe nebyl tak moc časově náročný, ale aby útok hrubou silou byl prakticky nemožný, protože by trval věčnost. Nebo dvě věčnosti.

MD5(heslo + salt), SHA-1(heslo + salt)

#22 Určitě jste slyšeli nebo četli o jakémsi saltu (sůl) a i já jsem ten pojem již zmínil. Používat salt při hashování hesel je nutné. Náhodně generovaný salt může být uložen v čitelné podobě v databázi a jeho úkolem je zabránit vyhledávání v předpočítaných tabulkách a také znemožnit nalezení uživatelů se stejným heslem (tzv. Birthday Attack). Stejné heslo by bez saltu mělo totiž stejný hash a to by v databázi šlo velice jednoduše poznat. Stejně jako v kuchyni tak i u hashování hesel záleží na tom, jak se sůl použije. Uvedený příklad je často k vidění, nicméně není ideální.

(・(エ)・)ノ HOW ABOUT NO

#23 Nástroje pro crackování hesel, jako například oclHashcat, počítají s touto variantou solení hesel (tedy připojení saltu před, nebo za heslo) a rovnou ji uvádějí v seznamu algoritmů, které umí louskat. Útočník má tedy hash i salt a může zaútočit hrubou silou, jako kdyby žádný salt použit nebyl. To samé platí pro slovníkové útoky. Nicméně, řekli jsme si, že hlavní úlohou saltu je bránit narozeninovým útokům a hledání v předpočítaných tabulkách, takže to vlastně nevadí.

HMAC(heslo, salt), hash_hmac(sha512, heslo, salt)

#24 O trochu zajímavější způsob solení je implementován v algoritmu HMAC (Hash-based message authentication code). Se saltem se provede XOR, připojí se k heslu, zahashuje a poté ještějednou to samé v bledě modré. Pokud použijete pomalou hashovací funkci, dá se to i používat.

(;¬_¬) CHALLENGE CONSIDERED

#25 Pomalá hashovací funkce je důležitá, ale i taková SHA-512 je jen 10× pomalejší, než SHA-256, 30× pomalejší, než SHA-1 a 80× pomalejší, než MD5. To není moc. HMAC tedy také není nejlepší volba. Pro ukládání hesel přece musí existovat vhodnější algoritmus a funkce.

bcrypt (Blowfish hashing)

#26 Však určitě. Takovým algoritmem je třeba bcrypt, někdy též nazýván jako Blowfish hashing. Algoritmus je relativně pomalý, sám o sobě podporuje salt i vícenásobné hashování (má parametr cost, který říká kolikrát se má hashovat a určuje tak, jak dlouho má hashování hesla trvat).

crypt() + salt=$2y$…, password_hash() & password_verify()

#27 V PHP podporuje bcrypt funkce crypt(), pokud se jí předá salt, který začíná $2y$, to funguje až od PHP 5.3.7, dřívější verze a salty začínající na $2a$ a $2x$ nepoužívejte. V PHP 5.5 jsou dostupné hezké a jednoduché funkce: password_hash() & password_verify(). Pro starší PHP jsou tyto ke stažení jako uživatelské funkce.

scrypt, PBKDF2

#28 Podobně dobré jsou i algoritmy scrypt a PBKDF2 (Password-Based Key Derivation Function). scrypt znemožňuje útoky hrubou silou tím, že potřebuje hodně paměti, ale v PHP je funkce dostupná jen jako extension. Od PHP 5.5 existuje hash_pbkdf2(), ale použít bcrypt je jistější.

Argon2, Password Hashing Competition

#29 Ale každá z těch uvedených funkcí má nějaký drobný problém. V létě 2015 se vyhlásily výsledky soutěže PHC a vybral se vítěz, Argon2, jehož varianta Argon2i bude absolutně nejlepší hashovací funkce na hesla. Zatím ještě není úplně dokončená, ale pak snad brzo bude i v PHP a bude se dát používat. (Aktualizace: v listopadu 2015 byl Argon2 dokončen, ale počkejte, až ho budou podporovat PHP funkce password_hash() a password_verify() a zatím je používejte v klidu dál.)

Ashley Madison

#30 I při použití správného hashování můžete leccos zkazit. Kontroverzní seznamka Ashley Madison měla hesla hashovaná bcryptem, ale kromě toho v jiném sloupci v databázi jen pomocí MD5. V létě 2015 byla hacknuta a data unikla na web. Útočníci samozřejmě útočili na slabší funkci MD5.

QUIET... I want to eavesdrop

#31 Pár dobrých rad na závěr. Hesla z prohlížeče nepřenášejte jen přes HTTP, použijte HTTPS se správným certifikátem, znemožníte tak jejich odposlech. Rovněž samotný přihlašovací formulář přenášejte přes HTTPS, jinak by ho po cestě mohl někdo upravit, třeba změnit atribut action.

←@→

#32 Nikdy neposílejte hesla e-mailem. Nikdy, ani po registraci. Uživatelé si je nikdy nezmění, nechají si to původní zaslané a e-mailová schránka je z dlouhodobého hlediska nezabezpečené úložiště, stačí ztratit chytrý telefon nebo laptop a máte problém. Taky vůbec netušíte, kudy všude daný e-mail prochází a spojení mezi poštovními servery jsou spíše nešifrovaná, disky v nich také.

ADMIN/ADMIN

#33 Pokud máte na webu funkci pro připomenutí zapomenutého hesla, tak to heslo nikdy neposílejte e-mailem v čitelné podobě. To vlastně ani nemůžete, protože ho v databázi máte zahashované bcryptem, že? Posílejte pouze za hodinu expirující jednorázový odkaz s náhodným tokenem, jiným pro každý takový pokus o reset hesla. Ten odkaz povede na stránku, kde si uživatel může nové heslo nastavit. Pokud uživatel zadá nesprávný e-mail, neříkejte mu to, vypište hlášku, jako kdyby zadal správnou adresu. Útočník by jinak mohl zjistit, jaké e-maily se v databázi nacházejí.

a76c8ba54d7be5d57daf858987c168a458009312

#34 Tak a to je vše, přátelé. Sledujte mě na Twitteru, pokud se chcete dozvědět, co se děje v mém světě PHP, bezpečnosti a výkonnosti. Pokud vás zajímá bezpečné ukládání hesel a vůbec webová bezpečnost, tak přijďte na školení (nejbližší termín: termín zatím nevypsán), které vedu. Díky a zas někdy!

Video záznam

Video záznam

YouTube

Michal Špaček

Michal Špaček

Vyvíjím webové aplikace, zajímá mě jejich bezpečnost. Nebojím se o tom mluvit veřejně, hledám hranice tak, že je posouvám. Chci naučit webové vývojáře stavět bezpečnější a výkonnější weby a aplikace.

Veřejná školení

Zvu vás na následující školení, která pořádám a vedu: