Náhodná čísla

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, on-line

Diskuse

Lukoko:

Pro zabavu doporucuju:

cat /dev/urandom | /dev/dsp

a potom <ctrl>+c
:-D
8.12.2006 01:54:09

Satai:

Pokud se nepletu, tak urandom neni specifikovan a je to rozsireni Linuxu a snad i Solarisu.
8.12.2006 08:55:31

ikona llook:

Spíš asi cat /dev/urandom > /dev/dsp, ne?
8.12.2006 17:36:00

tark:

Nestačilo by tohle?

<?php
$random
= (rand() * rand() / rand() + rand()) . rand();
?>
8.12.2006 10:31:41

ikona Jakub Vrána:

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.
8.12.2006 10:44:36

ikona Jakub Vrána:

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.
8.12.2006 10:45:36

mach:

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

Hds:

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

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?
27.10.2008 22:34:53

ikona Jakub Vrána:

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.
28.10.2008 04:46:48

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?
31.10.2008 03:46:35
avatar © 2005-2024 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.