Bezpečné přihlašování uživatelů

Školení, která pořádám

Dopsal jsem knihu

Článek vyšel na serveru Root.cz.

Pomocí protokolu HTTPS lze zajistit šifrovaný přenos všech informací a ideálně se tak hodí mimo jiné pro přihlašovací formuláře. Pokud tento protokol nemůžete použít (u malých projektů proto, že vám nevyjde vstříc hosting, u velkých z výkonnostních důvodů), přenáší se všechna data nešifrovaně a zdatný uživatel je může po cestě odposlouchávat. Jak jistě víte, nedávno byl obětí takového útoku Seznam.cz. Bezpečné přihlašování se ale dá zajistit i na nezabezpečeném protokolu.

Technika výzva-odpověď funguje tak, že server pošle klientovi výzvu, klient k této výzvě připojí své heslo a serveru pošle otisk tohoto spojení. Server na své straně provede totéž a pokud výsledky odpovídají, tak uživatele přihlásí, jinak ho odmítne. Bezpečnost tohoto řešení je založena na tom, že server každou výzvu posílá jen jednou a pokud se útočníkovi podaří odpověď klienta zachytit, k ničemu mu to neposlouží, protože stejnou výzvu už server nikdy nepošle.

Realizace pomocí PHP, MySQL a JavaScriptu

K technické realizaci tohoto řešení budeme potřebovat na straně serveru i klienta funkci na výpočet otisku hesla spojeného s výzvou. V PHP i dalších serverových jazycích jsou hashovací funkce k dispozici již v základu, takže máme situaci poměrně jednoduchou, na straně klienta budeme muset sáhnout po externí knihovně – např. JavaScript pro MD5 i SHA-1 nabízí v BSD licenci Paul Johnston.

Pro spojení výzvy a hesla by se dalo použít prosté zřetězení, o něco bezpečnější by ale mělo být použití kódu HMAC. V JavaScriptové knihovně je tento algoritmus už implementován, v PHP si funkci budeme muset napsat sami, naštěstí je poměrně jednoduchá:

<?php
/** Výpočet HMAC_MD5
* @param string klíč
* @param string data
* @return string 32 hexadecimálních číslic
*/
function hmac_md5($key, $data) {
    $blocksize = 64;
    if (strlen($key) > $blocksize) {
        $key = pack("H*", md5($key));
    }
    $key = str_pad($key, $blocksize, chr(0x00));
    $k_ipad = $key ^ str_repeat(chr(0x36), $blocksize);
    $k_opad = $key ^ str_repeat(chr(0x5c), $blocksize);
    return md5($k_opad . pack("H*", md5($k_ipad . $data)));
}
?>

Místo pack("H*", md5($s)) lze v PHP 5 použít md5($s, true). Pro výpočet HMAC lze použít také balíček Crypt_HMAC. Od PHP 5.1.2 lze použít také funkci hash_hmac.

Dále musíme zajistit ukládání použitých výzev. Pokud nám nevadí, že výzvy budou ze spojité řady (takže kdokoliv bude moci poznat, kolikrát se náš přihlašovací formulář použil), stačí nám k tomu jednoduchá tabulka:

CREATE TABLE challenges (
	id int NOT NULL AUTO_INCREMENT,
	created datetime NOT NULL,
	PRIMARY KEY (id)
);

Do této tabulky budeme při každém zobrazení přihlašovacího formuláře vkládat nový řádek. Při jeho odeslání se do této tabulky podíváme a pokud v ní výzvu nalezneme, tak ověříme heslo uživatele. Pokud souhlasí, tak výzvu smažeme, což je možné provádět i u zastaralých řádků (např. starších než 1 den), aby velikost tabulky zůstávala v rozumných mezích.

Zbývá vytvořit HTML formulář a celé to spojit dohromady:

<script type="text/javascript" src="md5.js"></script>
<script type="text/javascript">
function md5form(f) {
	f['password_hmac'].value = hex_hmac_md5(hex_md5(f['password'].value), f['challenge'].value);
	f['password'].disabled = true;
	f.submit();
	f['password'].disabled = false;
	return false;
}
</script>
<form action="" method="post" onsubmit="return md5form(this);">
<fieldset>
<?php
mysql_query("INSERT INTO challenges (created) VALUES (NOW())");
$challenge = mysql_insert_id();
?>
<input type="hidden" name="challenge" value="<?php echo $challenge; ?>" />
<input type="hidden" name="password_hmac" value="" />
Login: <input name="login" />
Heslo: <input type="password" name="password" />
<input type="submit" value="Přihlásit se" />
</fieldset>
</form>

Při zapnutém JavaScriptu se do skrytého formulářového pole password_hmac vloží otisk kombinace výzvy a MD5 hesla. MD5 hesla se používá proto, že na serveru je vhodné mít z bezpečnostních důvodů uložen pouze otisk hesla, takže při použití samotného hesla by server neměl jak spočítat výsledný otisk. Poté se zakáže pole se zadaným heslem (což způsobí, že se toto pole s formulářovými daty nebude posílat) a formulář se odešle. Po jeho odeslání se pole s heslem opět povolí, což se dělá jen kvůli tomu, aby se uživatel po neúspěšném přihlášení mohl vrátit v historii a heslo opravit. Pokud má uživatel JavaScript vypnutý, přenese se heslo jako prostý text, pomocí značky <noscript> je možné ho na toto riziko upozornit.

Na straně serveru můžeme heslo ověřit tímto kódem:

<?php
$logged = false;
$row = mysql_fetch_assoc(mysql_query("SELECT password_md5 FROM users WHERE login = '" . mysql_real_escape_string($_POST["login"]) . "'"));
if ($_POST["password_hmac"]) {
    $valid = (hmac_md5($row["password_md5"], $_POST["challenge"]) == $_POST["password_hmac"]);
} else {
    $valid = ($row["password_md5"] == md5($_POST["password"]));
}
if ($valid) {
    mysql_query("DELETE FROM challenges WHERE id = " . intval($_POST["challenge"]));
    if (mysql_affected_rows()) {
        $logged = true;
    }
}
?>

Pokud klient poslal pole password_hmac, ověříme heslo na jeho základě, jinak se spokojíme s textovým tvarem hesla. Za přihlášeného uživatele označíme tehdy, pokud souhlasí hesla a v tabulce challenges se nám podaří smazat zaslanou výzvu.

Poznámka k heslům s diakritikou

Funkce charCodeAt, kterou používá JavaScriptová knihovna, pracuje s Unicodovými kódy znaků. Knihovna z těchto kódů ve výchozím nastavení bere jen spodních 8 bitů (takže řada znaků koliduje), snadno se dá ale přenastavit tak, aby pracovala se 16 bity. Pokud již ale máte uložené otisky hesel uživatelů v jiném kódování, musí se kódování poměrně pracně převést – knihovna MD5 upravená pro Latin-2.

Závěr

S vynaložením nijak zvláštního úsilí můžeme zabezpečit své přihlašovací formuláře proti odposlechu. Použití HTTPS má samozřejmě i nadále svůj smysl, protože jednak šifruje všechna přenášená data a jednak dovolí ověřit i identitu protistrany. Technikou výzva-odpověď se ale dá bezpečnost přihlašovacích formulářů zlepšit i tam, kde použití HTTPS není z jakéhokoliv důvodu možné.

Kromě bezpečného přenášení hesla je vhodné zaměřit se i na jeho bezpečné ukládání na straně serveru a na vhodný způsob pamatování informace o přihlášenosti uživatele. Odchytávání hesel a jejich zveřejnění je ale jistě mediálně nejvděčnější…

Doplnění

Jak správně poznamenali čtenáři v diskusi, je tato technika velice citlivá na bezpečnost dat uložených v databázi. Proto nabízím její vylepšení:

  1. U každého uživatele bude uložen login, challenge a md5(hmac_md5(password, challenge)).
  2. Při přihlašování se AJAXem zjistí, jaký challenge uživatel naposledy použil, a pošle se hmac_md5(password, old_challenge) a md5(hmac_md5(password, new_challenge)).
  3. Na serveru se navíc ověří, jestli md5(old_hmac) souhlasí s tím, co je uloženo v databázi, a pokud ano, přepíše se to novými hodnotami.

Autorem této myšlenky je Paul Jonhston. Přikládám Proof of Concept.

Posílání výzev ze souvislé řady má kromě již zmíněné možnosti zjištění počtu zobrazení přihlašovacího formuláře ještě jednu nevýhodu – skript se může stát obětí útoku DoS. Pokud tomu chceme zabránit a nechceme si navždy pamatovat všechny náhodně vygenerované výzvy, můžeme výzvu ukládat do session proměnné.

Přijďte si o tomto tématu popovídat na školení Bezpečnost PHP aplikací (8.10.2010, Praha).

Jakub Vrána, Výuka, 12.4.2006, diskuse: 52 (nové: 0)

Diskuse

emu:

nezda se mi, ze by seznam byl obeti, obet podle me bylo 8 poluzaku modraka...seznam se stal maximalne obeti bulvaru
# 13.4.2006 01:01:53 reagovat

ikona Jakub Vrána:

Seznam svůj přihlašovací formulář neměl dostatečně zabezpečený, proto se stal obětí. Že to Nova nafoukla, je samozřejmě jiná věc.
# 13.4.2006 09:01:51 reagovat

Tomáš:

Blbost seznam ten člověk použil sniffer a za to nijak seznam nemůže. To je věc jedině té sítě ke které byli přihlášeni napanení uživatelé!
# 4.5.2006 18:43:07 reagovat

Marcus Flintus:

myslim, že asi nemá smysl vysvětlovat že se seznam nestal obětí, a že je prakticky nemožné se mezi data seznamu dostat (pokud nejste třeba jeden z jeho programátorů). Už jenom to klasické schema napovida

můj komp _ router _ server_________ . . . _________ WEBSERVER-SEZNAM _ DBSERVER-SEZNAM

- to je zjednodušení situace, a když si vezmeš na jakejch úsecích tady ta komunikace nemůže probíhat...

- hacknuti přihlašovacího formuláře je snad největší blbost co jsem slyšel.

- jedine, jak by se to dalo háknout je nahackovat 10 mašin mezi tebou a seznamem a na všech získat adminský práva. Ale takovejch lidí, co by to byli schopni to udělat je na světě pár. Zrovna jedoho znam, ale ten by neco takoveho neudelal - je na te svetle strane...
# 10.5.2006 00:18:15 reagovat

ikona Jakub Vrána:

Přihlašovací formulář Seznamu skutečně nebyl zabezpečen ani proti odposlechu. Toho se dá dosáhnout buď používáním HTTPS nebo alespoň zde popsaným způsobem. Díky této kauze si z toho vzali ponaučení a přihlašovací formulář už směřují na HTTPS. Jak ale podotýká http://www.root.cz/clanky/bezpecne-prihlasovani…/nazory/86670/ Michal Ludvig, tak v případě možnosti změny přenášených dat je to nezachrání. Přes HTTPS by se totiž měl přenášet i přihlašovací formulář a jediný z tohoto pohledu bezpečný způsob přihlášení je přes https://email.seznam.cz/.
# 10.5.2006 00:35:48 reagovat

Er3kCz:

Jezisi o cem to tu kecas proboha?
# 11.5.2009 14:15:46 reagovat

Marcus Flintus:

btw. cela ta afera byla o tom ze jeden lamer před 2 rokama vyposlouchal síťovou komunikaci v jedny počitačovy učebně v jedny škole. Pak si ten soubor s heslama uložil na svuj web aby si ho mohl doma stáhnout. a tak ho tam nechal a dočista na něj zapomněl. A co se nestalo! za rok a půl přišel MrGoogle a soubor našel, během pár měsíců to zjistila nova a udělala z toho "nabourání do mašin seznamu" tss...
---
# 10.5.2006 00:21:43 reagovat

Petr:

Chtěl bych se jen zeptat, jak poté, co nejbezpečněji zajistit přechod mezi stránkami po přihlášení?
# 29.4.2006 14:29:18 reagovat

krteczek:

Jen podotknu že jsem na seznamu viděl cca před rokem a půl vesele řádit jednoho vtipálka, který si na webzdarma umístil script fungující asi takhle:
rozšířil mezi obětmi zprávu o tom, že vytvořil stránku, kde po zaregistrování a zadání přihlašovacích údajů na seznam, byla dotyčným uložena v prohlížeči cookie pomocí které je identifikoval a automaticky přihlašoval na seznam...
a těch kteří na to skočili bylo dost... a on měl přihlašovací údaje od mnoha schránek...
je to prostě o blbosti lidí...
# 11.5.2006 16:05:32 reagovat

Spiedy:

Nebylo by lepsi u odeslaneho loginu doplnit <? addslashes ?>

Preci jenom co se s SQL dotazem stane, kdyz nekdo zada
' OR 1=1 OR login='a
tak mu to vrati seznam vsechn hesel :)
# 29.5.2006 13:01:43 reagovat

ikona Jakub Vrána:

Skripty očekávají zapnutou direktivu magic_quotes_gpc, je to napsané v patičce všech stránek.
# 29.5.2006 13:10:50 reagovat

ikona Jakub Vrána:

Kód jsem předělal na magic_quotes_gpc = Off a zmínil jsem to v patičce.
# 11.5.2009 05:31:51 reagovat

JFK:

Prihlaseni pokud heslo existuje je jasne, ale jak prenest heslo po registraci, aby pripadny utocnik (viz odposlouchavani po siti) ho nemohl zjistit. Pokud pouziji javascript ke kodovani, neni tezke zjistit jakym zpusobem.
# 12.7.2006 14:48:57 reagovat

ikona Jakub Vrána:

Postup je popsán na konci článku v části Doplnění.
# 12.7.2006 15:13:07 reagovat

Pavel:

zdravim,
hledal jsem jednoduchy challange/response, az jsem narazil tady na tento web.

v podstate mate zde vse, nemel by tedy byt problem jak to rozchodit.

pouzil jsem vas HTML formulář, a misto generovani challange z DB si ho generuji vlastnim scriptem. a v $_POST['password'] po odeslani tohoto formulare nachazim prazdno. v podstate, ta promenna ani neni definovana.

nevim jestli mam vadny nebo jiny md5.js soubor nebo jestli mam chybu nekde jinde v JS.
Ale pokud by to byla alespon trochu mozne byl bych rad kdyby mi nekdo poslal funkcni exampl.

potreboval bych nejaky exampl ktery nejdrive prozene password md5, pak jej zretezi s $challenge a opet prozene md5. cele se to odesle jako $_POST[password].
nevim si uz rady jak mam dale pokracovat, zaroven nechci posilat psw hole.

predem dekuji za jakekoliv exampl muj email nebo radu k vysledku shigi04[zavinac]seznam[tecka]cz
s pozdravem pavel
# 9.8.2006 01:32:37 reagovat

Pavel:

no uz jsem na to prisel: $_POST['password_hmac']
# 9.8.2006 01:56:25 reagovat

Hejda:

Proč se tady získává old_challenge AJAXem z challenge.php a ne SQLkem přímo z DB? :)
# 17.1.2007 19:10:38 reagovat

ikona Jakub Vrána:

Protože dopředu nevíme, který uživatel se bude přihlašovat.
# 17.1.2007 19:13:08 reagovat

Author:

Co si myslite o pouziti timestamp misto id? Ted mam na mysli pri pouziti v puvodni verzi bez AJAX. Prece jenom timestamp se meni rychleji, nez id ze souvisle rady a riziko duplicity je snad na hodne nizke urovni (prubeh scriptu ve stejnou vterinu pro vice nez jednoho uzivatele). Zaroven je mozne z db vypustit sloupec created, protoze timestamp interpretuje cas zobrazeni formulare take. Je mozno pouzit i funkci microtime() pro vyssi presnost a tim uz prakticky znemoznit vytvoreni duplicitnich zaznamu v db.
# 8.3.2007 09:11:46 reagovat

ikona Jakub Vrána:

Spíše než timestamp bych doporučil uniqid(). Potom je možné tuto hodnotu ukládat jen do session proměnné. Riziko duplicity sekund je pro toto použití příliš vysoké.
# 8.3.2007 11:32:23 reagovat

Ali:

Měl bych dotaz ten md5.js se dá někde stáhnout,popřípadě je součástí nákého z prohlížečů či byl vámi vytvořen? Zkouším tento příklad na svém počítači pomocí lokalního serveru EasyPHP a nefunguje mi a mám pocit že to je právě díky vadnému  či chybejícímu souboru m5.js. Předem dík za odpověď.
# 30.4.2007 18:40:47 reagovat

ikona Jakub Vrána:

http://pajhome.org.uk/crypt/md5/ - odkaz je uveden v článku.
# 2.5.2007 11:58:25 reagovat

Martin:

Ahoj,
tak mě tak napadlo, jak čtenáři správně poznamenali v diskuzi, kde se dá přijít na MD5 hash? Napadá mě, že pouze z databáze (protože z klienta se neposílá hash samotného hesla). Takže, nestačilo by ukládat hesla do databáze právě použitím algoritmu RSA? Kdyby někdo ukradl obsah databáze, RSA šifry mu jsou bez klíčů k ničemu. Kdyby někdo ukradl hodnotu posílanou na server, tak je mu to taky k ničemu, protože odezva platí vždy jen na jeden požadavek. A vlastní hodnotu posílanou na server si útočník vytvořit nemůže, protože nezná MD5 hash - případná zašifrovaná podoba hesla z databáze je mu k ničemu.
Šlo by to tak?
# 1.6.2007 17:03:50 reagovat

Miro:

Ahoj Jakube.
Pracujem teraz na novom projekte a tak som sa rozhodol, ze trochu pozmenim system prihlasovania, tak som vyuzil tento tvoj challenge-response a podla prilozeneho Proof of concept som to rozbehal.. udrzovanie informacii o prihlaseni som tiez realizoval tvojou metodou popisovanou v http://php.vrana.cz/prihlasovani-uzivatelu.php. Ja som to predtym riesil tak, ze informacia o prihlaseni bola ulozena v db, ale myslim, ze tvoja metoda celkom postacuje, takze nemusim klast zbytocne dotazy do db. No a ty v tvojom system pouzivas session_regenerate_id(). mas ho pouzite po uspesnom prihlaseni. no a sa chcem spytat, ze ci ho staci zavolat iba na tomto mieste, po prihlaseni, alebo ho treba/je lepsie ho volat po kazdom nacitani stranky, ked je uz uzivatel prihlaseny?
A este k tomu challenge-response. Chcel som prihlasovaci formular umiestnit tak, ze by sa stale zobrazovat na stranke, niekde na bocnom paneli, user by si browsoval stranku a ked sa bude chciet prihlasit, tak ho ma hned poruke a prihlasi sa. No lenze to by pri kazdom nacitani stranky, cize aj ked by si niekto pozeral stranku, cital clanky atd. a vobec by sa nechcel prihlasit, stale by sa kladol dotaz do db a stale by sa zvysovala hodnota challenge. To sa mi zdalo asi nie moc dobre, tak som prihlasovanie prelozil do samostatneho suboru a ked sa user chce prihlasit musi sa prekliknut na inu stranku, co mi pripada trochu neprakticke.. tak rozmyslam, ze ci by nebolo lepsie generovat challenge nejak inak alebo nevadi, ked po par mesiacoch bude mat challenge hodnotu napr. 1534341354214 ;)
# 23.7.2007 01:35:14 reagovat

ikona Jakub Vrána:

session_regenerate_id() je vhodné volat na každém místě, kde uživatel získá nějaká nová oprávnění - tedy typicky právě jen po přihlášení.

Vysoký challenge ničemu nevadí. Nicméně pokud používáš sessions, tak ho nemusíš ukládat do databáze, ale můžeš použít session proměnnou.
# 23.7.2007 09:59:55 reagovat

Miro:

Viem, ze vysoky challenge nicomu nevadi, len nejak tak sa mi to trochu nepozdavalo, ze bude stale narastat a narastat.. aby nahodou po case nepresiahol 2 147 483 647 ;).. ale asi si ho fakt zacnem generovat v sessions..
# 24.7.2007 02:52:02 reagovat

Miro:

a este mam jeden problemik ktory sa mi vyskytuje pri praci so sessions: prihlasim sa do mojej aplikacie vyuzivajucej sessions, potom taku hodinu alebo aj viac nic nerobim, potom kliknem na nejaky odkaz a som automaticky odhlaseny, pretoze sa cele pole sessions vymaze, takze aj udaj o prihlasenosti.. a nie som si isty, kde sa v cfg nastavuje cas, pocas ktoreho php uchovava premenne pre dane sedenie.. je to session.gc_maxlifetime ? aka je optimalna hodnota?.. dakujem
# 24.7.2007 03:10:00 reagovat

pokker:

trochu oneskorene ale preco vysoky challenge  ? co pouzitie
napriklad md5(rand(0,100000)); ???? nechapem ja som v scripte generoval nahodne retazce prave z rand'u je na tom nieco zle ?
# 4.8.2008 05:55:18 reagovat

LPL:

Nevím jestli jsem udělal něco špatně, ale když porovnám výsledek JS scriptu(hex_hmac_md5) s výsledkem PHP funkce hmac_md5() dostanu různé hodnoty. Čistý MD5 funguje správně, ale HMAC se liší. Můžete prosím někdo poradit?? Dík
# 25.9.2007 01:38:03 reagovat

ikona Jakub Vrána:

Uveď alespoň hodnoty, které používáš, a taky platformu klienta a serveru (především zda je operační systém 32- nebo 64-bitový).
# 30.9.2007 13:05:19 reagovat

LPL:

OK, sorry, ale nemuzu ted pozuit diakritiku. Po tve otazce, me napadlo zkusit to na 64-bitovym OS, protoze moje testy byly na starym Win98 a nasel jsem alespon stejne vysledky, ale pouze v pripade, ze 'salt'(data) byl povazovan za retezec, nikoliv int. Z toho tveho prikladu jsem to pochopil jako ze salt muze byt pouze cislo (viz. id_challenge) a cpal jsem do obou - PHP, i JS, stejne cislo. ...Ceka me jeste hodne objevu. Diky za reakci
# 13.10.2007 22:37:01 reagovat

ikona Jakub Vrána:

Funkci hex_hmac_md5() se musí předat řetězec, funkce hmac_md5() si řetězec z čísla sama vyrobí. V příkladu je f['challenge'].value vždy řetězec, i když je obsahem číslo. Pro použití čísla by bylo potřeba napsat třeba +f['challenge'].value.
# 15.10.2007 15:28:54 reagovat

Elijen:

Tahle diskuse je už asi mrtvá, ale stejně ...

Možná jsem něco přehlédl, ale podle mě tahle je tahle implementace NEFUNKČNÍ!

Na straně serveru se v implementaci výš používá pouze challange obdržený POSTem od klienta, což utočníkovy umožňuje odposlechnout libovolný challange a k němu patřící hmac a pak vnutit serveru svůj odposlechnutý challange s týmž hmacem a loginem uživatele => Efekt hashovnání == NULL ;-)
# 6.5.2008 15:04:06 reagovat

ikona Jakub Vrána:

Přehlédnul jsi kód
<?php
if (mysql_affected_rows()) {
   
$logged = true;
}
?>
Pokud výzva v tabulce nebyla, nepodaří se ji smazat a proměnná $logged se tedy nenastaví.
# 6.5.2008 15:14:41 reagovat

Alu:

V tomto kódu vidím drobnou (ale skutečně drobnou) bezpečnostní trhlinku v tom, že kdyby neexistovala tabulka challenges (někomu se povedlo ji smazat), funkce mysql_affected_rows() by vrátila hodnotu -1 a tudíž by došlo k přihlášení. Kdybych to psal já, určitě bych pro jistotu i tento případ ošetřil...
# 19.7.2010 18:11:44 reagovat

kolio:

Ahoj Jakube,

Omlouvam se za cestinu. Ulozil jsem soubory ze challange.zip na serveru, vytvoril databazi atd.
A zacal vyskouset ...
Ulozil jsem 2 uzivatele- a (heslo: "a"), b (heslo: "b")
Potom jem otevrel u IE7 2 Tabs u stejneho prohlizece a jsem zacal prihlasovat uzivatele: v prvni "Tab" jsem prihlasil "a" v druhem "Tab" "b" a opakoval - pri prvnim opakovani uzivatele se neprihlasili a v tabulce "users" se ulozili takove password_hmac_md5, ze uz se neda prihlasit.

V cem je problem - z toho, ze pouzivam  1 prohlizec a neco se plete se sessionem. Jak se to da upravit? Nebo ja neco delam blbe?

# 11.1.2009 02:05:44 reagovat

kolio:

Jakube rekni neco, cekam na to uz 9 mesicu :)
Asi otazka je hloupa, rekni alespon proc je to tak :)
# 6.10.2009 12:04:38 reagovat

kolio:

Je to podle me diskriminace, ostatnim odpovidas, me ne.

# 19.10.2009 16:58:24 reagovat

ikona Jakub Vrána:

Toto není soukromá poradna, ale veřejná diskuse. Odpovědět na tvůj dotaz může kdo chce. Nikdo na něj asi odpovědět nechce.
# 19.10.2009 17:00:14 reagovat

kolio:

Konecne - nejaka reakce! Je to uspech - za 9 mesicu. Ne rozumim proc jsi ochotni polemizovat formalni otazky jako co je ten forum a t.d. a nejsi ochotni odpovedet na konkretnou otazku tikajici se tveho clanku. Ja bych odpovedel i v kratce. Navic zda se mi ze jestli clovek pouzije tvuj model prihlasovani zpusobem jak jsem popsal v dotazu ne funguje to. Proc ne funguje? Kdyz nechces  odpovedet me rekni to alespon verejnosti :)
# 23.10.2009 08:20:55 reagovat

DPetr:

Ahoj Jakube,

mám takovou hloupou otázku. Pozoruji dění kolem bezpečnosti hesel a přihlašování a snažím se přijít na nějaké zjednodušení. Zdá se mi že většina řešení se snaží obejít nebezpečí decryptace hesla z nějakého hashe a zachycení komunikace o přihlašování . Ten druhý problém je nejjednodušeji řešitelný pomocí ssl přístupu ke stránkám . Není to dokonalé ale jako základní obrana stačí. Většinou se ale řeší problém unikátních hashes z hesla. Nebylo by jednoduché řešení použít dvojnásobný hash? myslim md5(md5(heslo)) popřípadě kryptaci hesla nejdřív sha1 a pak md5 či jakoukoli jinou kobinací dvou kryptovacích procesů? vím že s trochou času a dostatečně silným PC se dá databáze md5 hashes pro alfanumerická hesla do 8 znaků není těžko sestavit tabulku zpětného převodu. ale tabulku nějakých 6 nejčastějších kryptovacích algoritmů z md5 hashe dat si člověk jen tak nesestaví. Mám pravdu aspoň částečně nebo plácám kraviny?

Díky předem za odpověď
Petr
# 5.4.2009 04:46:13 reagovat

ikona Jakub Vrána:

Předpočítané tabulky lze odstavit přidáním saltu - to je správný a bezpečný způsob: http://php.vrana.cz/ukladani-hesel.php. Použití nezvyklé hešovací funkce (do čehož spadá i dvojité použití MD5) tabulky samozřejmě taky odstaví, ale neřeší další neduhy (např. že dva uživatelé se stejným heslem mají stejný heš).

Opakovaná aplikace hešovací funkce bezpečnost nezvyšuje, čistě teoreticky ji může naopak snížit, vysvětlení je ale o něco složitější. Jde o to, že v hešování nejspíš budou vznikat cykly, kterými se zmenšuje prostor hesel, která je potřeba prozkoumat.
# 6.4.2009 03:12:22 reagovat

Krkel:

Ahoj, snažím se pochopit princip tohoto návrhu, ale nejde mi do hlavy. Můžeš mi Jakube prosím říct, čemu přesně toto řešení zabranuje. Díky
# 11.5.2009 11:09:37 reagovat

j.:

Zdravím, chtěl bych se zeptat, co je to this v :

return md5form(this);

Pak ještě jak píšeš " Na straně serveru můžeme heslo ověřit tímto kódem:....." Tak to je myšleno při ověření na začatku nebo pak i v průběhu pohybu mezi stránkami namísto session&cookies ?

Moc dík za odpověď.j.
# 2.6.2009 12:49:44 reagovat

ikona Jakub Vrána:

this je odkaz na aktuální objekt, v obsluze události formuláře tedy na formulář.

Ověření hesla probíhá jen na začátku, pak už pomocí session.
# 4.6.2009 03:06:14 reagovat

j.:

A ještě jedna otázečka, kam mam ve formuláři tus tránku, na kterou to bude pokračovat po tom ověření např. neco.php Diky za odpověď. j.
# 2.6.2009 13:16:17 reagovat

Vojtěch Dobeš:

Zdravím. Rád bych se zeptal, zda-li existuje nějaké spojení challenge/response metody při přihlašování a metody solení otisků hesel náhodně generovaným saltem při registraci. Při googlení jsem nalezl návrh použít jako salt např. uživatelské jméno - je to oproti náhodně generovanému saltu větší bezpečnostní riziko?
# 10.7.2009 18:37:55 reagovat

ikona Jakub Vrána:

Login není špatný adept, ale není ani ideální. Pokud může být login krátký, tak jeho přidání heš dostatečně nezesložití, takže pro jeho rozlousknutí půjdou lépe využít Rainbow tables.
# 11.7.2009 18:00:33 reagovat

ikona Marek:

Ahoj, mohol by si sa pozrieť na ten priložený Proof of Concept na riadok 10 v súbore login.php:
<?php
$password_hmac_md5
= md5(hmac_md5($_POST["password"], $_POST["challenge"]));
?>
Ide o prihlásenie pri vypnutom javascripte, nejak sa mi nezdá to použitie $_POST["challenge"] keďže taká položka sa neodosiela cez formulár, a následne sa zapisuje do databázy iná hodnota na 16-tom riadku ten istý súbor:
<?php
mysql_query
("UPDATE users SET challenge = '$_SESSION[challenge]', password_hmac_md5 = '$password_hmac_md5' WHERE login = '$_POST[login]'");
?>
Rozdiel je v tom, že HASH hodnota hesla je tvorená z $_POST["challenge"]="" ale do stĺpca challenge sa uloží hodnota $_SESSION[challenge]="hodnota". Potom by mal nastať problém pri ďalšom overení hesla, keďže pri použití challnege z DB nedostaneme rovnaký odtlačok ako je uložené heslo. Snáď som čosi neprehliadol.
# 18.6.2010 10:18:18 reagovat

ikona Jakub Vrána:

Díky za upozornění, skutečně to bylo špatně. Opravil jsem to.
# 18.6.2010 13:15:04 reagovat

Tori:

Dobrý večer,
mohl byste se podívat na JScriptovou funkci hex_hmac_md5()? Jejich autor zřejmě použil opačné pořadí parametrů, než je u obdobné funkce v PHP, tedy hex_hmac_md5(key, data). Omlouvám se, pokud jsem něco přehlédla.
# 31.7.2010 00:05:30 reagovat

ikona Jakub Vrána:

Pokud máš na mysli funkci hash_hmac(), tak pořadí parametrů je skutečně opačné.
# 31.7.2010 05:32:39 reagovat

Vložit příspěvek

Používejte diakritiku. Nelze používat HTML značky, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

© 2005-2010 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.