« 1 2 »
Autor Zpráva
jakre
Profil
Zdravím,

pátral jsem ve starších vláknech diskuze po správném ukládání hesla do databáze. Narazil jsem na odkaz s návodem. Potřeboval bych poradil, jak porovnat zadané heslo s heslem hashovaným v databázi. Součástí mého skriptu je následující PHP kód:

$stm = $db->prepare('SELECT * FROM users WHERE username = ? AND password = ?');
    $stm->execute([$_POST['username'], $_POST['password']]);

    if ($stm->fetch(PDO::FETCH_OBJ))
    {
        $_SESSION['login'] = true;
        header('Location: index.php');
    }

V datábazi je ručně zadané přihlašovací jméno (plaintext) a zahashované heslo - neprovádím registrace.
juriad
Profil
On ten článek není kdovíjak dobrý, autor doporučuje použití rychlé funkce SHA-256 a nezmiňuje použití soli.
V dnešní době bych řekl, že je chybou použít cokoli jiného než funkce password_hash a password_verify.

Musíš vědět, jakým způsobem byl ten hash v databázi vypočítán. Pak stačí provést přesně tu samou posloupnost operací, jaká byla provedena při registraci.
V případě těch funkcí password_hash a password_verify se používají při generování hashe náhodná čísla, která se ukládají spolu s hashem, proto je pro ověření hesla nutná odlišná funkce než pro vytvoření hashe.
jakre
Profil
juriad:
Článek je téměř 10 let starý :-)

Musíš vědět, jakým způsobem byl ten hash v databázi vypočítán. Pak stačí provést přesně tu samou posloupnost operací, jaká byla provedena při registraci.
Psal jsem, že je v databázi heslo zadáno ručně již zahashované, tudíž potřebuji pouze ověření při přihlášení.

Postupoval bych tak, že bych si vypsal hash pro mé heslo a zadal ho ručně do databáze. Nevím, jak ověření integrovat do mého kódu [#1].
juriad
Profil
jakre:
Budu předpokládat, že je to funkce z článku pro SHA-256; pak je to:
$stm->execute([$_POST['username'], hash('sha256', $_POST['password'])]);
Keeehi
Profil
A takto pro password_verify
$stm = $db->prepare('SELECT * FROM users WHERE username = ?');
$stm->execute([$_POST['username']]);
 
if ($row = $stm->fetch(PDO::FETCH_OBJ)) {
    if (password_verify($_POST['password'], $row->password)) {
        $_SESSION['login'] = true;
        header('Location: index.php');
    } else {
        // špatné heslo
    }
} else {
    // uživatel neexistuje
}
jakre
Profil
Děkuji.

Použil jsem password_hash, vygeneroval si hash pro své heslo a uložil ho do databáze.

$heslo = password_hash("heslo", PASSWORD_DEFAULT);
echo 'Heslo je: <strong>'.$heslo.'</strong>';

Na stránce o funkci password_hash jsem našel více možností, jak mohu heslo hashovat. Zvolil jsem PASSWORD_DEFAULT a zajímá mě, proč nemusí být tato metoda zmíněna někde v kódu pro ověření hesel [#5] - jak ověření probíhá? Porovnává se přeci formulářem zaslané heslo s tím, které je uložené v databázi (což nemůže souhlasit, protože se zaslané heslo nikde nepřevádí podle PASSWORD_DEFAULT).

Chtěl bych se také zeptat, jestli byste mi doporučili přidat tzv. solení hesla.
juriad
Profil
jakre:
Funkce password_hash se o vše postará, všimni si výstupu té funkce (dvakrát zahashované heslo 123456):
$2y$10$BP7vt2cn5Vd.8l5hM8yVPuv9OzOGTurM1ZoL0NSEaDFcS10/asTCG
$2y$10$YThT9qO2Z6Yc08mIlunVB.osTuqy/5v.2P0/FKvAOuuPRJ2P55ywq
2y udává algoritmus hashe; ten vlastně vybíráš pomocí toho parametru PASSWORD_DEFAULT (ano, máš použít tento parametr)
10 udává sílu hashe - jde o nějaký interní parametr použitého algoritmu
22 znaků za $ - náhodná sůl, která byla použita při hashování
zbytek - samotný hash hesla

Tedy funkce password_verify zná všechny podrobnosti proto, aby mohla hash z hesla vypočítat za stejných okolností (použít stejný algorithmus, stejnou sílu, stejnou sůl).
Keeehi
Profil
jakre:
Chtěl bych se také zeptat, jestli byste mi doporučili přidat tzv. solení hesla.
Ano. Ovšem, jak už juriad ukázal, už to děláš aniž bys o tom věděl. V tom je právě kása funkcí password_*, jsou vytvořeny tak, aby je bylo lehké použít a pokud je necháš v plně automatickém módu, jsou dostatečně bezpečné. Dokonce se předpokládá, že se jejich vnitřek bude časem měnit s tím, jak se postupně vyvíjejí algoritmy a bezpečnostní best practices. Bez zásahu do kódu, jen změnou PHP verze se mohou nové hashe vytvářet už novou bezpečnější metodou.
jakre
Profil
Děkuji za vysvětlení.

Vypadá to velmi bezpečně, když se používá náhodná sůl. Znamená to, že i v případě úniku hashovaných hesel z databáze bude náročné dostat se k původnímu heslu? Nebo může být heslo naopak odchyceno cestou k serveru, a to i v případě použití HTTPS, kde se kód provádí?
Joker
Profil
jakre:
Znamená to, že i v případě úniku hashovaných hesel z databáze bude náročné dostat se k původnímu heslu?
To záleží na použitém hashovacím algoritmu.
A na tom, jak bezpečné heslo uživatel má.

Dokud nemá bezpečnostní díru ten hashovací algoritmus, útočník nemá moc jiných možností, než hrubou sílu: Vytvářet hashe pro různá hesla a doufat, že se trefí.

Samozřejmě pokud by uživatel měl heslo 123456, útočník ho odhadne možná už na první pokus.

Sůl sice zabrání alespoň tomu, aby si útočník z databáze mohl jednoduše vytáhnout uživatele s triviálním heslem, ale pokud se útočník zaměří na jednoho uživatele s triviálním heslem, pochopitelně to heslo uhodne.
jakre
Profil
Joker:
Aha. Z pohledu databáze a jejího napadení je to tudíž v pořádku, může se ale útočník dostat k heslu, které se odesílá formulářem metodou POST ke zpracování?

Například ho nějak odchytit z komunikace mezi uživatelem a serverem.
Joker
Profil
To samozřejmě možné je.

Na straně serveru se to riziko dá minimalizovat použitím HTTPS.

Pro ještě paranoidnější zabezpečení existují postupy, kdy se samotné heslo mezi klientem a serverem vůbec neposílá.
midlan
Profil
Joker:
Můžeš nastínit tyto postupy?
Joker
Profil
Viz challenge-response authentication.

Je tam ale nevýhoda, že de facto musí server znát otevřené heslo, resp. většinou je v databázi sice hash, ale jako heslo se používá ten hash (tj. útočníkovi teoreticky stačí znát hash hesla).
Funguje to tak, že při přihlášení server vytvoří nějaký jednorázový (pokaždé jiný) text, zapamatuje si ho a pošle klientovi. Na klientovi uživatel zadá heslo, to se použije jako klíč pro zašifrování serverem zaslaného textu a výsledek (text zašifrovaný heslem) se pošle zpátky na server.
Server vezme původní text, zašifruje ho skutečným uživatelovým heslem z databáze a podívá se, jestli se výsledek shoduje.

Je to odolné proti odposlechu, ale zase zranitelné na ukradení databáze. Při použití hashe (na serveru je hash, klient nejdřív udělá hash zadaného hesla a tím pak zašifruje text ze serveru) sice útočník nezjistí skutečné uživatelovo heslo, ale k přihlášení na server mu stačí i ten hash (na klientovi vynechá fázi hashování a podstrčí rovnou hash z databáze pro zašifrování toho textu).

Zdokonalit by to šlo použitím asymetrického šifrování, pak by to už byly normální digitální podpisy.
Uživatel by musel mít soukromý klíč a server by znal jeho veřejný klíč.
Přihlášení by fungovalo tak, že by server pošle nějaký jednorázový text a řekne „podepiš mi tohle“. Uživatel ten text digitálně podepíše a pošle zpátky na server. Ten pomocí jeho veřejného klíče ověří podpis a přihlásí uživatele.

Útočníkovi nepomůže odposlech (získá jen ten jednorázový text) ani krádež databáze (získá jen veřejný klíč), akorát uživatel se musí přihlašovat soukromým klíčem, což je složitější, než jen zadat heslo.
jakre
Profil
Joker:
Nedovedu si představit obtížnost takového napadení databáze nebo odposlechu. Je mi ale jasné, že je bezpečnější samotné heslo vůbec neposílat.

Útočníkovi nepomůže odposlech (získá jen ten jednorázový text) ani krádež databáze (získá jen veřejný klíč)
Jak by útočníkovi pomohl odposlech v případě, že použiju pouze hashování hesla a HTTPS?
Keeehi
Profil
jakre:
použiju pouze hashování hesla a HTTPS
To jsou 2 rozdílné věci. Pokud by útočník odposlechnul hash toho hesla, mohl by se s ním přihlásit. A pokud tomu odposlechnutí má zabránit HTTPS, pak můžeš rovnou posílat nehashované heslo když tomu tak věříš.

V důsledku jde tedy o to, že pokud se útočníkovi povede odposlechnout ať už heslo, nebo jeho hash, může se jimi také přihlásit. Jediný důvod, proč by bylo lepší posílat jen hash hesla je ochrana lidí, kteří používají stejné heslo pro více služeb. Pokud by pro každou službu používali jiné heslo, bylo by úplně jedno, zda by se posílalo heslo nebo jeho hash.

Jinak ani HTTPS není ve 100% případů bezpečné. I proti němu existuje celá řada útoků. Pokud tě bezpečnost zajímá, mohu doporučit stránky Michala Špačka který se různými druhy bezpečnosti zabývá a hlavně o tom umí srozumitelně přednášet.
Joker
Profil
jakre:
Nedovedu si představit obtížnost takového napadení databáze nebo odposlechu.

To je silně závislé na konkrétní situaci. U databáze jaké máte heslo, jak zabezpečený je hosting, kde se skladují zálohy, kdo všechno k nim má přístup, apod.

Odposlech záleží jaký a koho.
Např. na frekventovaném místě udělat WiFi hotspot s názvem *nějaká firma v okolí* free WiFi a sledovat provoz těch, kdo se přes něj připojí, je celkem triviální.
S trochou sociálního inženýrství by takhle asi šlo zaměřit i konkrétní oběť.
jakre
Profil
Má v tom případě smysl používat HTTPS, když lze šifrovaná komunikace překonat (resp. heslo nějak odposlechnout)?
Joker
Profil
jakre:
To je podobná otázka jako jestli má smysl používat zámek na dveřích, když ho lze překonat.
jakre
Profil
Joker:
V podstatě máš pravdu.

Ale pokud vím, tak je jednoduché v případě HTTP modifikovat obsah webu (server > klient) a podstrčit tak klientovi odlišný web. Výhoda HTTPS tedy spočívá zejména zde?
Keeehi
Profil
Bezpečnost není vlastnost. Nemůžeš o něčem říct, že to bezpečné je nebo není. Je o tom potřeba přemýšlet jako o míře. S dostatečnými prostředky můžeš prolomit jakoukoli ochranu. V důsledku jde tedy jen o to zda hodnota získaných věcí/informací je pro útočníka větší než hodnota prostředků, které by musel vynaložit na jejich získání.
Pak je tu druhá strana, cena, jakou jsi ochoten zaplatit, aby jsi ochránil své věci/informace.

Když to převedeme do reálného světa, tak zloděj nebude organizovat loupež, která ho bude stát 100 000$ na prolomení zámku sejfu, když v něm bude 10$.

A naopak, pokud budeš mít 200$, nebudeš si kupovat sejf za 50 000$ na jejich ochranu. Levněji tě vyjde si těch 200$ nechat párkrát ukradnout.

Lze tedy doporučit použít vše, co si můžeš dovolit nebo co tě nic nestojí. HTTPS si nejspíše budeš moct dovolit.
Martin2
Profil *
Keeehi:
Jinak ani HTTPS není ve 100% případů bezpečné. I proti němu existuje celá řada útoků.
To je trochu zjednodušující pohled. Pokud jako provozovatel neuděláš žádnou chybu v konfiguraci (což není tak náročné) a také infrastruktura, která k šifrování poskytla klíče nebo ta, která ho provádí není nějak kompromitována (což většinou lze předpokládat), dá se přenos v HTTPS vrstvě považovat za 100% bezpečný, respektive jeho překonání není reálné žádnými ani hypotetickými prostředky.
TomášK
Profil
Martin2
HTTPS není neprorazitelné při tom, jak se běžné používá. Uživatelům stačí zelený zámeček, málokdo kontroluje samotný certifikát. Stačí tedy jedna kompromitovaná certifikační autorita, která je nastavena jako důvěryhodná a problém je na světě. Vybavuju si aféru některých notebooků Dell, kdy byl v instalaci i privátní klíč k certifikační autoritě od Dellu, které byla nastavena jako důvěryhodná, něco podobného snad mělo i Lenovo. Man-in-the-middle má celkem slušnou šanci vylákat z uživatele heslo (nebo hash, podle toho, co se posílá). Dá se tomu bránit (HPKP, DANE mělo-li by podporu v prohlížečích), ale většinou to nebývá nastavené.
Určitě je dobrý nápad HTTPS používat, ale brát ho jako 100% záruku už ne.
Martin2
Profil *
TomášK
Je to transportní zabezpečení. Nikdo se netváří, že by HTTPS chránilo zeleninu v lednici proti plísni. A co se týče malwaru v koncových stanicích (i když tomu tak Dell a výrobci „bezpečnostních“ softwarů asi neříkají), to se jako MITM neoznačuje (i když používá podobné techniky).
TomášK
Profil
Martin2:
Z toho, co jsi napsal, jsem nabyl dojmu, že heslo poslané přes HTTPS je v podstatě neukradnutelné. Což podle mě není pravda, MITM pravděpodobně heslo dokáže ukrást. Důvěryhodné CA v koncových stanicích jsou příklad, jak může jednoduše podvrhnout certifikát serveru, což se při útoku MITM hodí. HTTPS jako protokol bezpečný je, nicméně typický uživatel ho bezpečně nepoužívá.
Martin2
Profil *
TomášK:
heslo poslané přes HTTPS je v podstatě neukradnutelné
Ano, po trase je neukradnutelné.

MITM pravděpodobně heslo dokáže ukrást.
Ne, nedokáže. Útoku MITM brání podpisy kořenových certifikačních autorit – ty jsou u nekompromitovaného počítače pro útočníka nepřekonatelnou zárukou bezpečnosti.
TomášK
Profil
Martin2:
ty jsou u nekompromitovaného počítače ...
Tu je to, v čem se neshodnem. Já nepovažuju seznam certifikačních autorit, které má běžný uživatel nastavené, za důvěryhodný, ty ano.

Myslím, že můžeme diskuzi ukončit, asi nejde rozhodnout, kdo má pravdu. Nechť je každý paranoidní dle svého uvážení :)
Martin2
Profil *
TomášK:
Já nepovažuju seznam certifikačních autorit, které má běžný uživatel nastavené, za důvěryhodný
Na tom ovšem stojí veškerá zabezpečená komunikace světa. Banky, platby, elektronické podpisy, certifikace softwaru… Tomuto systému je možné buď důvěřovat, nebo žít v pralese.
TomášK
Profil
Martin2:
Problém toho systému je, že jakákoliv certifikační autorita může vydat certifikát pro jakýkoliv web. Certifikační autorita výrobce zařízení nebo nějaké čínské firmy jde použít k vydání certifikátu na stránky banky a uživatel si toho nevšimne. Pro věci, kde o něco jde, se používá 2-faktorová autentizace (platby, banky) nebo se kontroluje, zda je certifikát podepsaný konkrétní CA, nikoliv jakoukoliv ze seznamu, který někdo dodal.
Kolik uživatelů postřehlo, že na ně Avast provádí (nebo prováděl) MITM? Když je na serveru nastavené HTTPS, dá se spolehnout na to, že komunikace mezi uživatelem a serverem není odposlouchaná. Ale už se nedá spolehnout na to, že uživatel zjistí, že komunikuje s někým jiným, kdo se za server vydává.
Keeehi
Profil
Martin2:
Pokud jako provozovatel neuděláš žádnou chybu v konfiguraci (což není tak náročné)
Na tom ovšem stojí veškerá zabezpečená komunikace světa. Banky, platby, elektronické podpisy, certifikace softwaru.
No s bankami to zas tak slavné není. Kdyby všechny měly tu bezpečnou konfiguraci, nemusel Špaček provádět každý měsíc jejich skenování nastavení https.

Je jasné, že louskat RSA může louskat jen málokdo. Je klidně i možné, že to provést nelze. Největší problém https však je že, se ho útočník může pokusit zbavit. A je úplně jedno, jak jako administrátor nastavíš tvůj server, pokud bude útočník od začátku sedět na komunikaci mezi tebou a uživatelem, může mu měnit jeho požadavky v případě, že napíše doménu do adresního řádku. Jediná obrana proti tomu zatím je být na seznamu, který je vestavěn v prohlížečích a říká pro které domény má být použito rovnou https.
« 1 2 »

Vaše odpověď

Mohlo by se hodit

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0