Náhodná čísla

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

Pokud v aplikaci potřebujeme používat náhodná čísla, nejspíš použijeme nějaký generátor pseudonáhodných čísel, protože k lepším zdrojům náhody nebudeme mít přístup. Tyto generátory mohou vykazovat poměrně dobré vlastnosti, problémem je, jak je inicializovat. Dříve to bylo potřeba dělat ručně funkcí srand, resp. mt_srand, od PHP 4.2.0 se o to postará PHP za nás (pokud inicializaci neprovedeme ručně). Výchozí inicializace používá aktuální čas, ID procesu a hodnotu z lineárního kongruenčního generátoru, který pro svou inicializaci také používá aktuální čas a ID aktuálního procesu nebo vlákna. Z toho plyne, že pokud by se posloupnost náhodných čísel pokusil někdo uhádnout, tak má při znalosti času požadavku docela slušnou šanci.

Pokud to je pro nás nepřijatelné, můžeme do inicializace generátoru pseudonáhodných čísel přidat vlastní konstantu, která uhodnutí podstatně ztíží. Na Unixu lze pro inicializaci nebo pro vlastní získávání náhodných čísel také použít speciální soubor /dev/random, který při čtení vrací náhodná data:

<?php
/** Načtení náhodných dat ze souboru
* @param int minimální hodnota, výchozí je 0
* @param int maximální hodnota, výchozí je getrandmax()
* @param string název souboru s náhodnými daty, výchozí je /dev/random
* @return int náhodné číslo z rozsahu $min - $max (včetně)
*/
function random($min = 0, $max = null, $filename = "/dev/random") {
    if (!isset($max)) {
        $max = getrandmax();
    }
    $return = 0;
    $range = 1;
    $fp = fopen($filename, "rb");
    while ($range < $max - $min + 1) {
        $return = 256*$return + ord(fgetc($fp));
        $range *= 256;
    }
    fclose($fp);
    return $min + floor($return / $range * ($max - $min + 1));
}
?>

Při zapnuté extenzi OpenSSL se dá od PHP 5.3.0 použít také funkce openssl_random_pseudo_bytes.

Jakub Vrána, Výuka, 8.12.2006, diskuse: 11 (nové: 0)

Diskuse

Lukoko:

Pro zabavu doporucuju:

cat /dev/urandom | /dev/dsp

a potom <ctrl>+c
:-D

Satai:

Pokud se nepletu, tak urandom neni specifikovan a je to rozsireni Linuxu a snad i Solarisu.

ikona llook:

Spíš asi cat /dev/urandom > /dev/dsp, ne?

tark:

Nestačilo by tohle?

<?php
$random
= (rand() * rand() / rand() + rand()) . rand();
?>

ikona Jakub Vrána OpenID:

Z hlediska náhodnosti je to pořád totéž. Jakmile se mi podaří uhodnout, z jakého místa v posloupnosti pseudonáhodných čísel jsem je začal brát, tak už je jedno, co s nimi provádím a kolikrát.

ikona Jakub Vrána OpenID:

Koho toto téma zaujalo, určitě si rád přečte i pěkný a hutný článek o tom, jak /dev/random a /dev/urandom funguje: http://swordfish.buslab.org/?p=67.

mach:

Nebo v jednom dile (2. nebo 3.) The Art of Computer Programming je cela cast venovana generovani nahodnych cisel.

Hds:

OT: aneb jak se ještě dá získat náhodné číslo: http://thedailywtf.com/forums/thread/105411.aspx

Karel:

1) Dá se jako seed použít výraz z microtime a nějakého počitadla přístupů, které se zvyšuje s každým požadavkem?
2) Lehce top-topic, ale neslyšel někdo o *hardwarovém* generátoru náhodných čísel?

ikona Jakub Vrána OpenID:

1. Seed je lepší vůbec nepoužívat, protože ať už ho vezmu z jakéhokoliv zdroje, vyresetuji stav generátoru náhodných čísel, takže se potom útočníkovi snadněji odhaduje.

2. Hardwarový generátor je v Linuxu mapován právě na /dev/random - viz http://en.wikipedia.org/wiki//dev/random.

ikona v6ak:

Teď si to čtu znovu a vzpomínám si na http://www.phpguru.cz/clanky/nenechte-uhodnout-sid#comment-56 .
Problém má jen ten linaární kongruenční generátor?

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, 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:

avatar © 2005-2018 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.