Drobkův blog
obrázek kategorie

DROBKŮV BLOG

Generátor náhodných hesel (10.04. 2008)

Nedávno jsem hledal generátor hesel v php. Stačilo pověřit google a hnedle se na mě valila hromada výsledků. Jaké však bylo mé zděšení, když jsem na otevřel první stránku http://ivorius.com/weblog/skript-na-generovani-nahodnych-hesel Rozhodl jsem se, že vám ukážu, jak to dělá Drobek. Poznámka: vzhled kódu je optimalizovaný pro Operu (a firefox) na optimalizaci pro rozmary IE nemám čas ani chuť.


Původní kód včetně původních poznámek. Chybné řádky jsou podsvíceny červeně. Někdy jde jen o připomínku či drobnou změnu, jindy jsou však chyby zásadní (co se efektivity skriptu týče) a začátečníkům (pro které údajně autor píše) mohou posloužit leda jako odstrašující příklad.

0: function Random_Password($length){
1:   srand((double)microtime()*1000000);2:   // inicializace random generátoru 
3:   $possible_charactors = "abcdefghijklmnopqrstuvwxyz123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
4:   //možné znaky 
5:   $string="";6:   while(strlen($string)<$length) {7:   // opakuj cyklus dokud počet znaků string je menší než length 
8:     $string .= substr($possible_charactors, rand()%(strlen($possible_charactors)),1);9:   // vybereme náhodný znak z množiny znaků pro heslo 
10:    }
11:  return ($string);
12:}

Nyní rozeberu jednotlivé chyby pěkně řádek po řádku:

  • Řádek 1: od verze php 4.2.0 se již srand aktivuje automaticky. Drobná chybka.
  • Řádek 5: Opět drobná chybka, tentokrát se to projeví i v efektivnosti. Dvojité uvozovky se používají jen v případě, že chceme převádět např. "\n" na nový řádek. Jindy je vždy efektivnější napsat jednoduché uvozovky a případně řetězit pomocí tečky. není to velká chyba, ale takovýto dobrý zvyk vám může v budoucnu ušetřit (v některých aplikacích stále ještě cenné) mikrosekundy.
  • Řádek 6: Tak tady si autor zvolil velice nešťastně jak cyklus, tak opakovací podmínku.
    Vždyť on by při každém průchodu cyklem zjišťoval délku nově vznikajícího řetězce (kterou v každém cyklu inkrementuje) a porovnával ji s požadovanou délkou hesla. Vždyť generujeme od nuly, pokaždé jeden znak, takže víme, kolikrát cyklus proběhne.
  • Řádek 8: další veliká hrůza a to z několika důvodů:
    1. funkce rand() se již po 32768 použitích opakuje a generuje stejná hesla. Není proto pro případného útočníka problém nechat si vygenerovat 2!! hesla a dopočítat hesla předchozích uživatelů. Lepší je použít funkci mt_rand() která má stejné parametry, ale je rychlejší a využívá jiných (a bezpečnějších) algorytmů.
    2. Proboha proč používat substr? Vždyť možné charaktery máme v proměnné a proměnná typus tring je co? Pole charů. Proč tedy zbytečně vytvářet jednoprvkový řetězec na jeden znak a poté jej převádět na znak a přidat do řetězce, když můžeme jednoduše získat přímo n-tý znak bez vytváření podřetězce.

Pokud se vám uvedené chyby (hlavně cyklus a zjišťování podřetězce) zdají býti zanedbatelnými, doporučuji vám vrátit se k základům jazyků jako je c (nikoliv c++), abyste si uvědomili, jak věci v php fungují. To že nemusíte deklarovat proměnné a máte k dispozici hromady funkcí je výhodou pouze do té doby, dokud vám to zaručuje luxus a nikoliv prasácky napsané pomalé a neefektivní kódy o kterých vlastně ani nevíte, jak vevnitř fungují.

Následuje mnou přepracovaný kód, který vykonává totéž:

0:function Rand_pass($delka_hesla) {
1:  $mozne_znaky = 'abcdefghijklmnopqrstuvwxyz123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
2:  $vystup = '';
3:  $pocet_moznych_znaku = strlen($mozne_znaky)-1;
4:  for ($i=0;$i<$delka_hesla;$i++) {
5:    $vystup .= $mozne_znaky[mt_rand(0,$pocet_moznych_znaku)];
6:  }
7:  return $vystup;
8:}

Efektivita se tím z původních zhruba (N!)*M operací substr snížila na N krát přístup k I-tému prvku pole, kde I<=M Toto je samozřejmě pouze hrubý odhad, nikoliv výpočet.


Komentáře k článku

Nebojte se napsat, že se vám článek líbil, nebo nelíbil a proč. Rád si přečtu i váš názor ;)

Systém podporuje Gravatary. Email je nutné vyplnit, avšak nezobrazí se.

Přidat nový příspěvek





Gravatar darktatka   04.01. 2009 22:23


ja vim ze to je pase, ale tak me prastilo do oci ty possible_charactors. possible_characters je snad klicovy slovo?
Jinak ja sem generovani hesel resil trochu vic s rozmachem - http://github.com/DarkTatka/password_generator/tree/master (samozrejme v ruby)

Gravatar Drobek   03.10. 2008 07:31
www stránky: http://drobek.nadrobeny.net

Děkuji. Je možné, že jsem si toto neuvědomil. Nejspíš jsem si nebyl jistý, zda mt_rand vrací i horní mez.

Gravatar Jiří Darmovzal   02.10. 2008 16:56
www stránky: http://www.darmovzal.cz

Na řádce 3 doporučuji odečíst z $pocet_moznych_znaku 1, předejdete tím vybráním znaku mimo index $mozne_znaky funkcí mt_rand na rádce 5.