Autor Zpráva
pmg
Profil
Pro generování identifikátoru přihlášení používám hash pseudonáhodného čísla. Setkávám se s názorem, že to není bezpečné. Nedokážu si ale představit, jak by případný útočník postupoval.

Předpokládám, že funkce rand (třeba i v MySQL) vychází kromě aktuálního počtu mikrosekund také z id procesu nebo nějaké hashe paměti. Netuším, jak by útočník mohl dodatečné údaje zjistit na soukromém serveru. V případě freehostingů by to do jisté míry mohl vyzkoušet. Dále by musel vědět, kde se v kódu daná funkce vyskytuje, a přesný čas požadavku. Považuji to za celkem nereálné.

Pseudonáhodné generátory mohou ve výsledku vracet jen omezenou množinu čísel, ale ta je snad pořád víc než dostačující.

Zajímalo by mě, zda považujete uvedené řešení za bezpečné nebo jak problém řešíte. Můžete se podívat na Wikipedii: Cryptographically secure pseudorandom number generator.
peta
Profil
pmg
Bezpecne neni md5, protoze md5 je pouze souctovy algoritmus pro kontrolu dat a neni staveny pro vytvareni hesla.

Abych ti to objasnil.
mas nahodny retezec "abcdefghijklamnop09874652375", ve tvem pripade nahodne cislo, na tom ted nesejde.
Z tohoto retezce se pro jeho rekneme ctvrtiny spocitaji binarni soucty (or: nebo xor.
1 3 4 2 - (vymyslena cisla)
tyto soucty se jeste nejakym algoritmem spoji, treba xor a jeste ten soucet se spoji:
1 3 4 2 63 85 33 (vymyslena cisla)
A to je cela md5. Jenom je to ve vetsim meritku, algoritmus je trochu jinak postaveny, ze da vice znaku.
Ok, a proc to teda neni bezpecne?
Cisla z algoritmu vychazeji v intervalu od-do.
Problem je v tom, ze jestlize heslo obsahuje znaky "afhgp" pak cisla budou mit hodnotu a b c, pokud jine znak, pak d e f.
Takze si odectes hodnoty z md5, vypises, ktere znaky ma zkouset pro ktere misto a cele desifrovani se zjednodusi napr na 10.000 hodnot, coz je tak do 5minut bez problemu. Pozor, ziskas kolizi. Md5 je souctovy algoritmus a soucet 1+5 a 2+4 muze byt stejny 6. Cili heslo nemusi byt stejne, jako mas ty, ale bude davat stejny soucet jako tve heslo. Tim padem mas nekonecne kombinaci hesla. Leda bys omezill min-max delku, pak mas konecny pocet kombinaci a v tom pripade se ten algoritmus trefi do tveho cisla.

google.com klima md5 tunel
google.com md5 collision

co se tyce funkci rand, tak nepredpokladej, najdi si literaturu
cz.php.net/rand
mysql na mysql strance
tam je popsane, jakym zpusobem se ziskava cislo a mam pocit, ze jedno z toho neni pocitane z cisla krystalu casu
cili uplne nahodna hodnota se nejlepe ziska pres mikrosekundy
md5(rand()*funkce())
list($micro_sec,$sec) = explode(" ",microtime());
pmg
Profil
Děkuji za odpověď. Algoritmus MD5 je podle mě pro popsaný účel nejlepší z běžně používaných hashů, neboť je rychlý a pro přirozená čísla v dostačujícím rozsahu nevrací stejný řetězec. Z toho vyplývá, že je zbytečné pátrat po kolizích: útočník jedinečný identifikátor nesmí získat.

Takže tedy ještě k mému dotazu. Způsob inicializace generátoru závisí na prostředí, následující algoritmus má za úkol (jen) vymámit z podobných seedů co nejproměnlivější hodnoty. Pokud je použitý algoritmus známý (často není moc možností), závisí už jen na kvalitě seedu. Zajímalo mě, proč je inicializace založená na aktuálním počtu mikrosekund, popř. dalších pseudonáhodných údajích (to opravdu nebyl jen předpoklad, používá se třeba id procesu nebo hash paměti), považována za málo bezpečnou.

peta
co se tyce funkci rand, tak nepredpokladej, najdi si literaturu
V referenci jsem to zkoušel, než jsem založil toto vlákno; když tak poprosím o konkrétní odkaz, jestli jsi byl úspěšnější. Můj dotaz byl ale položen spíše obecně: Je možné (při troše snahy) odhadnout výstup běžného pseudonáhodného generátoru (tj. který nepoužívá speciální hardwarové komponenty ap.)?
krteczek_jinde
Profil *
pmg: Nic není nemožné, Toyota... ;-)

myslím si, že tohle by byla dost velká náhoda aby někdo odhadnul 32 místný náhodný text. uvažujme:
na webu může být v během 48 hodin, řekněme 100000 useru, to je 100000 náhodně vygenerovaných identifikátorů, kolik že je možných kombinací znaků u MD5?
určitě identifikátory ukládáš do databáze, takže uniqe nad sloupcem s identifikátory zaručíš že nebude použit jeden klíč dvakrát.

pokud se ti to zdá málo, nadraď md5 za sha1, kde je délka 40 znaků a počet kombinací je o několik řádů větší

no a nebo si udělej fci která ti ty identifikátory bude generovat z nějaké sady znaků a podle tvého přání
pmg
Profil
krteczek_jinde
Díky za odpověď.
určitě identifikátory ukládáš do databáze, takže uniqe nad sloupcem s identifikátory zaručíš že nebude použit jeden klíč dvakrát

Každé přihlášení má jako primární klíč přirozené číslo (auto_increment), samotný hash je ve zvláštním sloupci. Má to několik výhod:
1) Indexování nad číselným sloupcem je rychlejší: primární klíče na sebe navazují.
2) Vyhledání patřičného řádku je rychlejší.
3) Ani při větším množství přihlášení se neomezuje počet možných tvarů řetězce (více přihlášení může mít stejný hash). Útočník se musí soustředit jen na konkrétní přihlášení.
4) Aby nebylo nutné posílat spolu s hashem zvlášť i id, vytvořil jsem si přihlašovací proceduru, která vrátí 40znakový hexadecimální řetězec (8 znaků id, 32 hash).

Samotný identifikátor se hashuje, aby měl jednotnou délku a nebylo možné rychle najít určitou posloupnost mezi generovanými čísly. Použití SHA by teoreticky už tak velký počet kombinací (2^128) zvýšilo. Limit klade spíše funkce rand, která nevrací ani 2^48 kombinací (MySQL). Zvýšení bezpečnosti by se mohlo dosáhlo spíš přidáním nějaké konstanty k náhodnému číslu, protože jinak není pro útočníka složité si možná čísla a odpovídající hashe předgenerovat, a zjistit použité náhodné číslo mnohem rychleji.

Vlastní funkce pro vygenerování hashe by přinesla podobné zvýšení bezpečnosti (ale kódy by musely zůstat skryté, na rozdíl od použití konstanty, která by se mohla definovat třeba při instalaci systému).

Stále ale platí, že je potřeba použít pseudonáhodný generátor, o kterém si někteří myslí, že není bezpečný. Já s takovým tvrzením nemohu souhlasit (viz první příspěvek). U webových aplikací navíc není složité kontrolovat počet požadavků a útok znemožnit.
krteczek
Profil
pmg
U webových aplikací navíc není složité kontrolovat počet požadavků a útok znemožnit.

To jsem zapoměl zmínit, navíc lze například útok na přihlašovací formulář ztížit třeba generátorem náhodných znaků, součtovým formulářem, javascriptem, ...

Suoustřeď se na obranu před XSS a jinými bezpečnostními dírami
http://cs.wikipedia.org/wiki/Cross-site_scripting
http://www.security-portal.cz/clanky/xss-cross-site-scripting-hacking. html
http://securitycompass.com/exploitme.shtml
pmg
Profil
Díky za odkazy. Chtěl jsem dojít k řešení, které bude co nejjednodušší a přitom bezpečné. Nemělo by být také závislé na utajení algoritmu. Zajímavou možností je mít nějaký salt uložený v databázi a před (popř i po) použití ho pseudonáhodně pozměnit. Stačí použít inkrementaci.

Dobře inicializovaný generátor s velkou periodou (třeba mt_rand v PHP) by měl pro daný účel také stačit. Při použití Mersenne Twister stačí znát 624 po sobě jdoucích hodnot, a dá se uhodnout další. Když každý skript generátor zinicializuje (dělá se to automaticky), mělo by to stačit, protože se interně použijí nějaké další, náhodnější hodnoty (/dev/urandom).

Problém je ale možné řešit už na straně klienta. Třeba zaznamenávat několikrát za sekundu pozici myši a kombinovat to s mikročasem. Šetřil by se výkon serveru a bylo by to i bezpečné;-)

S hashováním hesla je to složitější a vězí zde mnohem větší riziko, ale jak píšeš, nejlepší je hashovat s nějakým saltem už na straně klienta.

XSS je kapitola sama pro sebe, dobrá připomínka. Díky.
krteczek
Profil
Ještě něco: pokud se jedná o http komunikaci můžeš si jen myslet něco o bezpečnosti... Po nešifrovaných kanálech se ti o ní může jenom zdát.

Řešil bych to klasickou $_SESSION, vnutil jí dobu platnosti (bud dohodou přes hosting, nebo pokud to jde tak ini_set())
Můžeš si třeba do té sejšny ukládat i hash toho co s tebou komunikuje (ip, prohlížeč, další blbosti) a jen to ověřit při dalším načtení stránky (je to on? nebo se něco změnilo? pokud je vše stejné, jedeme dál, pokud není, tak odhlášení). Jo budou mamrat ti co se jim mění ip za pochodu, ale normálním lidem se to neděje, to znamená bud jede přes nějakou anonymizer proxy, nebo je přes mobil a jede v pendolinu z práglu do ovy, buhužel, je to odpojí, můžeš se vymluvit na ztrátu signálu :-D

Zaměřil bych se na sql inject, php inject, XSS, další věci...

Pokud chceš bezpečnost, tak jdi do https, jinak je to jen hraní ;-)
pmg
Profil
Naprosto souhlasím. Je možné nechat uživatele přihlásit se vícekrát (tzn. ukládat přihlášení do zvláštní tabulky). Může tak pracovat s několika prohlížeči nebo na různých místech synchronizovaně.

jdi do https, jinak je to jen hraní
Taky si říkám, proč se zabývat kvalitou generátoru klíče, když ten klíč (a všechna ostatní data) vzápětí pošlu přes http. Tak alespoň pomocí js zaručit, aby nikdo nedostal plain text heslo.

Zde je funkce pro bezpečnější generování klíčů v mysql. Používá tabulku settings pro uchování hodnoty seed. Ta se může nastavit voláním

DO set_seed('Náhodná hodnota');

Pokud tak neuděláme, zinicializuje se pomocí rand.


delimiter |

CREATE FUNCTION get_random_hash()
RETURNS binary(40)
BEGIN
DECLARE `result_random_hash` binary(40) DEFAULT '';
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' BEGIN END;

SELECT `random_hash`
INTO `result_random_hash`
FROM `settings`
WHERE `setting_id` = 1;

IF `result_random_hash` = '' THEN
SELECT set_seed(rand())
INTO `result_random_hash`;
END IF;

RETURN SHA1(CONCAT(`result_random_hash`, UUID()));
END;
|

CREATE FUNCTION set_seed(`new_seed` binary(40))
RETURNS binary(40)
BEGIN
SET `new_seed` = CONCAT(SHA1(`new_seed`), UUID());

INSERT INTO `settings` SET
`setting_id` = 1,
`random_hash` = `new_seed`
ON DUPLICATE KEY UPDATE
`random_hash` = `new_seed`;

RETURN `new_seed`;
END;
|

delimiter ;

CREATE TABLE `settings` (
`setting_id` tinyint(1) unsigned NOT NULL DEFAULT '1',
`random_hash` char(40) NOT NULL DEFAULT '',
PRIMARY KEY (`setting_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
krteczek
Profil
pmg: koukám na to, to nebude psané v PHP... Asi něco od MS, co?

To ukládání infa do tabuly zvlášť jen zbytečně přidává další dotaz na databázi.
Jestli je to v dané chvíli ten kdo se přihlásil, ověřuji právě těmi informacemi o dotyčném. Nějak takto:
//poslane $id je obsah uložený v session
function kontrolaIdentifikace($id)

	{

		if(getIdentifikation() == $id)

			{

				return true;

			}

		# je to špatne, odhlasime usera

		$this->odhlaseni();

	}
function getIdentifikation()
	{
		$ip = !empty($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : '';
		$prohlizec = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER["HTTP_USER_AGENT"] : '';
		$forward = !empty($_SERVER["HTTP_X_FORWARDED_FOR"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"] : '';
		return sha1($ip . $prohlizec . $forward);
	}

pmg
Profil
Funkce jsou psané v samotném SQL. Lepší databázové systémy (MySQL až od páté verze) umožňují kromě klasických dotazů pro čtení a úpravy definovat funkce, které se uloží do databáze a dají se později volat. To je dobré, když je potřeba s daty složitěji manipulovat, není tak nutné posílat je několikrát tam a zpět (databáze <=> PHP).

Bastlit takovýto kód není nic příjemného, SQL je pro tyto účely dost nepřehledný, kód se protahuje a plno věcí je podporovaných jen tak napůl, takže je člověk rád, když to nějak funguje. Přináší to ale potom značné usnadnění složitějších úkonů vázaných čistě na databázi. Dá se také nadefinovat funkce, která se spustí při určitém zásahu do tabulky (tzv. trigger). To se dobře uplatní třeba pro různé přehledové tabulky, pro udržování konzistence dat nebo optimalizaci výkonu.

Uvedený příklad řeší jen samotné vytvoření klíče. MySQL nenabízí kdovíjak silný pseudonáhodný generátor. Funkce UUID() by měla vracet pokaždé jiný klíč, a to i třeba pro souběžně spuštěné dotazy na různých serverech. Výsledek je ale založen především na čase a dá se lehko odhadnout.

Pokud se ale i lehko uhodnutelné číslo spojí s dostatečně náhodnou hodnotou, výsledek bude bezpečný. Tuto vysoce náhodnou hodnotu je potřeba někam uložit a je dobré mít možnost ji změnit. Samotný dotaz podle primárního klíče (pro přečtení hodnoty) je velice rychlý, navíc je spouštěn ze samotné SQL funkce.

V PHP bychom pro daný účel vystačili s mt_rand. Je ale čistší ucelené úkoly, které může databáze zvládnout sama (třeba ověřit heslo, přidat záznam o přihlášení a vrátit klíč), ponechat na ní. Proto ta složitost.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

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