Regulární výraz bezpečné heslo, aneb jak testovat silná hesla

RegExp strong password je celkem běžnou záležitostí, ale přesto si s tím řada programátorů nedokáže poradit. Tady je jeden návrh mého řešení jak testovat heslo s jedním velkým písmenem, jedním číslem a minimálně 8 znaky. A také způsob jak takové heslo vytvořit.


Na tento článek mne přivedl jeden kolega a způsob jakým tento problém řešil. Jeho řešení ukazuji v následujícím příkladě.

Stanovené podmínky:

  1. minimálně 8 znaků
  2. minimálně jedno velké písmeno
  3. minimálně jedno číslo
  1. function checkPwd($pwd) {
  2. if (strlen($pwd)<8) return false; 
  3. if (!preg_match("~[a-z]+~", $pwd)) return false;
  4. if (!preg_match("~[A-Z]+~", $pwd)) return false;
  5. if (!preg_match("~[0-9]+~", $pwd)) return false;
  6. return true;
  7. }

Bohužel nechtěl mi věřit, že to lze zapsat jedním regexpem a tak musel vzniknout tento článek.

Moje Řešení

  1. $password=array("SuperSilneHeslo2009", "supersilneheslo2009", "supersilneheslo", "Supersilneheslo2009", "su2009", "Su2009");
  2. function checkPass($p) {
  3. $regexp="/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(.){8,}$/";
  4. if (preg_match($regexp, $p)) return true;
  5. else return false;
  6. }
  7. foreach($password as $p) {
  8. if (checkPass($p)) echo $p." ...OK";
  9. else echo $p." ...BAD";
  10. echo "<br/>";
  11. }

Vyzkoušejte funkčnost sami.

A jak takové heslo automaticky vytvořit?

  1. function createPassword($length) {
  2. $chars="234567890abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  3. $i=0;
  4. $password="";
  5. while ($i <= $length) {
  6. $password.=$chars{mt_rand(0,strlen($chars))};
  7. $i++;
  8. }
  9. return $password;
  10. }
  11. $password = createPassword(8);
  12. echo "Your 8 character password is: $password";

Pro další informace doporučuji seriál na intervalu, zejména tyto články Perl-compatible regulární výrazy v PHP - tvrzení v praxi, podmíněné subvýrazyPerl-compatible regulární výrazy v PHP - lokální modifikátory, tvrzení a manuál php preg_match.

UPDATE 22.1.2009

Cílem tohoto článku nebylo vytvořit generátor bezpečných hesel a nebyl na něj kladen důraz, avšak na základě příspěvků v diskusi je potřeba původní kód přehodnotit.

Výsledek generátoru nezaručuje splnění všech daných podmínek a je tedy nutné výsledné heslo ještě doplnit o tři dané podmínky.

  1. // funkce vytvoří pole o unikátních náhodných číslech v rozsahu $count
  2. function uniqueRand($min, $max, $count) {
  3. // nutno doplnit ochrany typu min>max, count>(max-min) apod. to neni v prikladu reseno
  4. $arr=array();
  5. for ($i=0;$i<$count;$i++) {
  6. do {
  7. $r=mt_rand($min, $max);
  8. } while(in_array($r, $arr));
  9. $arr[$i]=$r;
  10. }
  11. return $arr;
  12. }
  13. function createPassword($length) {
  14. $chars="1234567890abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  15. $i=0;
  16. $password="";
  17. while ($i <= $length) {
  18. $password.=$chars{mt_rand(0,strlen($chars))};
  19. $i++;
  20. }
  21. // a ještě náhodně nahradíme malé, velké písmeno a číslo v řetězci
  22. $arr=uniqueRand(0, $length, 3);
  23. $password{$arr[0]}=chr(mt_rand(48, 57));
  24. $password{$arr[1]}=chr(mt_rand(65, 90));
  25. $password{$arr[2]}=chr(mt_rand(97, 122));
  26. return $password;
  27. }
  28. $password = createPassword(8);
  29. echo "Your 8 character password is: $password";

komentáře

RSS Komentáře k článku RSS Komentáře   Add to Google
21.01.2009 23:05 | Anonym (plazboz) | jednicka

Není mi jasný význam proč v $chars chybí číslice jedna. Má to nějaký význam nebo jde o překlep? Díky

22.01.2009 09:57 | Administrátor | Re: jednicka

ano, překlep, článek vznikal jen kvůli regulárnímu výrazu, tohle jsem na poslední chvíli jen přihodil a vytvářel to právě kolega (nechce být jmenován), dnes opravím máte oba pravdu

22.01.2009 00:01 | Anonym (David Grudl) | dvojka

Funkce createPassword bohužel nezaručuje, že vytvoří heslo podle stanovených podmínek, jen s určitou pravděpodobností. Je potřeba ji doplnit o tři příkazy, které na náhodnou pozici vloží číslo, malé písmeno a velké písmeno.

22.01.2009 12:30 | Administrátor | Re: dvojka

vyřešeno, pokud jsem se v rychlosti někde nesekl

22.01.2009 14:56 | Anonym (Jakub Vrána) | Zpětné lomítko

Ve výrazu (?=.*d) chybí zpětné lomítko.

24.01.2009 03:00 | Administrátor | Re: Zpětné lomítko

opraveno, stále si nezvykám na že mi to fckeditor automaticky odstraní

23.01.2009 00:58 | Anonym (Timy) | šílenost

Upřímně řešeno to druhé řešení je šílenost, ve které se nikdo nevyzná, první řešení je možná naivní, ale daleko přehlednější…

24.01.2009 00:17 | Administrátor | Re: šílenost

Nic Vám nebrání napsat lepší řešení, zveřejním ho i s odkazem na Vaše stránky

11.08.2009 14:11 | Anonym (Fandik) | Re: šílenost

První řešení není naivní, je správné. Předčasná optimalizace není na místě a vždy je kořenem všeho zla. Dokážu si představit, že podmínky pro heslo se v čase budou rozšiřovat a doplácávat je pak do „Moje Řešení“ je trvale neudržitelné.

30.07.2009 00:00 | Anonym (Jan) | Na straně klienta

Ještě bych dopsal to samé v JavaScriptu a napojil to na onExit nebo na časovač. Aby to bylo fakt košér ;-)

Jméno
Název
Text
Lze používat Texy! syntax. Příklad syntaxe: "text odkazu":odkaz, **tučně**, *kurzíva*, `code`. PHP kód uzavírejte do <?php ... ?> a JavaScript do <script> ... </script>