2009-06-24 18 views
17

La función rand() de PHP no da buenos números aleatorios. Entonces comencé a usar mt_rand(), que se dice que da mejores resultados. ¿Pero qué tan buenos son estos resultados? ¿Hay algún método para mejorarlos de nuevo?Generar números aleatorios criptográficamente seguros en php

Mi idea:

function rand_best($min, $max) { 
    $generated = array(); 
    for ($i = 0; $i < 100; $i++) { 
     $generated[] = mt_rand($min, $max); 
    } 
    shuffle($generated); 
    $position = mt_rand(0, 99); 
    return $generated[$position]; 
} 

Esto debería darle números aleatorios "perfectos", no?

+0

Este es un duplicado de una de mis preguntas http://stackoverflow.com/questions/5611/better-random-generating-php – UnkwnTech

+0

La versión más reciente de php tiene un [PRNG criptográficamente seguro] (http: // stackoverflow. com/a/31443898/1090562). –

+3

Si alguien está leyendo esto, omita la respuesta aceptada porque [esta respuesta es la correcta] (http://stackoverflow.com/a/31443898/2224584). Si está atascado en PHP 5, consulte [random_compat] (https://github.com/paragonie/random_compat). –

Respuesta

32

Pseudorandom number generators (PRNG) son bestia muy complejo.

No hay verdaderos generadores de números aleatorios "perfectos"; de hecho, lo mejor que se puede hacer de las funciones matemáticas son pseudoaleatorias: parecen lo suficientemente aleatorias para la mayoría de los propósitos.

De hecho, realizar acciones adicionales a partir de un número devuelto por un PRNG realmente no aumenta su aleatoriedad, y de hecho, el número puede ser menos aleatorio.

Por lo tanto, mi mejor consejo es, no perder el tiempo con los valores devueltos por un PRNG. Use un PRNG que sea lo suficientemente bueno para el uso previsto, y si no lo es, busque un PRNG que pueda producir mejores resultados, si es necesario.

Y francamente, parece que la función mt_rand usa el Mersenne twister, que es un PRNG bastante bueno, por lo que probablemente sea lo suficientemente bueno para el uso más casual.

Sin embargo, Mersenne Twister no está diseñado para usarse en ningún contexto de seguridad. Consulte this answer para obtener una solución para usar cuando necesite aleatoriedad para garantizar la seguridad.

Editar

Hubo una pregunta en los comentarios qué realizar operaciones en un número aleatorio puede hacer que sea menos aleatorio. Por ejemplo, algunos PRNG pueden devolver números más consistentes y menos aleatorios en diferentes partes de los bits: el extremo superior puede ser más aleatorio que el extremo inferior.

Por lo tanto, en operaciones en las que la gama alta se descarta y se devuelve el extremo inferior, el valor puede ser menos aleatoria que el valor original de regresar de la PRNG.

No encuentro una buena explicación por el momento, pero la he basado en la documentación de Java para el método Random.nextInt(int), que está diseñado para crear un valor bastante aleatorio en un rango específico. Ese método tiene en cuenta la diferencia en la aleatoriedad de las partes del valor, por lo que puede devolver un número aleatorio mejor en comparación con implementaciones más ingenuas como rand() % range.

+1

¿Cómo puede ser 'menos aleatorio'? – karim79

+4

karim: Dado que todos los PRNG se basan en cálculos que solo generan números aparentemente aleatorios, existen ciertos inconvenientes. En principio, generar números "aleatorios" va en contra de todo lo que puede hacer una computadora, ya que las computadoras son, por diseño, máquinas deterministas. Dependiendo de qué cálculos se realicen en los números para generar bits aleatorios, hay algunos que muestran aleatoriedad estadísticamente buena y otros que no. Eso depende de tu generador, sin embargo. Los LCG tienen bits bajos débiles, otros tipos tienen bits altos débiles, otros incluso no muestran ninguna debilidad. Es un tema muy complejo. – Joey

+1

coobird: Random.nextInt (int) de Java no _puede proporcionar bits más débiles. Lo que hace es eliminar el sesgo debido a la operación del módulo que preferiría valores más pequeños. Me llevó dos días entender por qué funciona, pero lo hace de forma muy elegante. Pero 600 caracteres es demasiado corto para esto. La parte que descarta los bits de orden inferior (debido a la menor aleatoriedad) se realiza en Random.next (int): return (int) (seed >>> (48 - bits)). Como puede ver, como máximo 32 de los 48 bits del LCG se devuelven allí, lo que hace un buen trabajo eliminando los bits "débiles" de bajo orden. – Joey

1

No existe el número aleatorio "perfecto". No importa la definición subjetiva de "perfecto" que tengas. Solo puedes lograr un pseudoaleatorio.

Simplemente estaba tratando de apuntarle en la dirección correcta. Hiciste una pregunta sobre números aleatorios perfectos, incluso si fue perfecto entre comillas. Y sí, puedes mejorar la aleatoriedad. Incluso puede implementar algoritmos heurísticos o "naturales", tales como "ruido atmosférico", pero aún así, no es perfecto, de ninguna manera.

+0

Pero incluso si solo hay números pseudoaleatorios, puedes mejorar la aleatoriedad, ¿no? – caw

+0

La aleatoriedad es simplemente la inversa de nuestra capacidad para predecir el resultado ... por lo que un dígito binario aleatorio perfecto es solo 50% 'aleatorio'. Crear números aleatorios "verdaderos" requiere eliminar patrones predecibles entre los números, y la mejor manera de hacerlo es mediante el uso de procesos que los humanos realmente no entendemos muy bien; como decaimiento radioactivo y ruido atmosférico. Estas fuentes están disponibles en línea, busque HotBits y Random.org para esas fuentes, respectivamente. – Steve

12
<?php 
    function random_number(){ 
     return 4; // return generated number 
       // guaranteed to be random 
    } 
    ?> 

Bromas aparte, que se está metiendo una cuestión filosófica de lo que es "aleatorio" o lo que es "mejor". Idealmente, desearía que sus números aleatorios tuvieran algunos patrones en el transcurso de su procedimiento. En general, la hora del sistema se usa como la semilla, pero también usé el número aleatorio anterior como la semilla, la cantidad aleatoria anterior fue la semilla. El problema es que con una computadora lo suficientemente poderosa y un conocimiento completo del funcionamiento del hardware y la función del generador, usted podría predecir el conjunto completo de números generados. Por lo tanto, si tuvieras una computadora lo suficientemente poderosa (algunas personas ponen a Dios en esta categoría) que conociera todas las variables y funciones posibles del universo, entonces podrías predecir cada evento que sucedió o sucederá. La mayoría de los generadores de números aleatorios están bien por sí solos, pero si conoces a alguien que puede ver los patrones, es más probable que sean como el chico de Beautiful Mind y deberías llevarlos a una clínica.

By popular demand: D

+4

No estoy seguro de que las personas que no leen xkcd obtengan la broma. Probablemente habría sido mejor vincularlo. – Davy8

+0

Debería declinarte por no vincularlo. – UnkwnTech

+0

en su lugar solo insertaré la imagen – UnkwnTech

17

no estoy seguro de que lo que has hecho "mejora" la aleatoriedad. Por lo que puedo entender, generas 100 números aleatorios y luego eliges aleatoriamente uno de ellos.

De lo que puedo recordar de mi curso de probabilidad, esto probablemente no aumenta la aleatoriedad, ya que si hay un sesgo subyacente en la función del generador (mt_rand()), entonces todavía se reflejará de alguna manera en la salida .

+0

Lo has entendido correctamente. Gracias por tu respuesta. Ahora sé que no puedo mejorar la aleatoriedad con cálculos adicionales. – caw

+0

¿Qué pasaría si tuviera dos algoritmos de RNG diferentes? ¿Has mejorado las cosas entonces? – Carbon

13

¿De qué manera es mt_rand() "malo"?

Por ejemplo: si favorece un cierto número. Digamos que mt_rand (1, 10) favorece los números bajos en el rango, es decir, "1" y "2" ocurren en promedio más de 10% cada uno. Entonces su "mejora" aún sufriría del mismo problema.

Selección de un número al azar de una secuencia defectuosa se está defectuosa.

+0

Sí, esto es exactamente lo que estaba pensando. – Peter

+0

Gracias, bien explicado. – caw

+0

+1 ¡Muy bien hecho! ¡Buena explicación! – Melsi

-1

No es posible generar verdaderos números aleatorios, lo mejor que puede esperar es pseudoaleatorio, que es lo que proporciona rand(), su función no es más aleatoria que rand(). Echar un vistazo a este http://en.wikipedia.org/wiki/Random_number_generator

+0

Quiere decir mt_rand(), la función rand() en php ha demostrado ser defectuosa. – Gerry

+0

mt_rand() y rand() no son más defectuosos que cualquier otro psuedo-RNG, hasta donde yo sé. – UnkwnTech

+3

La diferencia radica en el algoritmo y las propiedades estadísticas comprobables de los números aleatorios. Y rand() no * es * suficiente para muchas aplicaciones. Además, el Mersenne Twister es lo suficientemente rápido y genera números de mayor calidad para que las personas sin un conocimiento profundo del campo puedan sugerir MT19937 de forma segura en lugar del rand incorporado(). – Joey

1

Si no te gusta construida en rand(), probablemente no debería usar PHP de su incorporada shuffle() tampoco, ya que parece que se construirá en su rand().

estoy a mitad de camino de que el shuffle "estándar de la industria" ahora es el Fisher-Yates aleatoria.

2

Todo depende de lo que necesita para ese número al azar :) Para mí ShuffleBag es el mejor :)

2

Editar: Mi comentario ya no es válida. Por favor, vea la siguiente respuesta: https://stackoverflow.com/a/31443898/109561


supongo que está preocupado acerca de la distribución de mt_rand(). Lo he probado y es muy plano, y ambos límites son inclusivos.

he añadido mi prueba a los comentarios de la documentación para mt_rand() en el manual de php, pero fue eliminado por un moderador tonto debido a la política que están sin aliento demasiado tiempo para entrar aquí.

+0

Debería también tenga en cuenta que para los números aleatorios verdaderos (si existe tal cosa) se distribuirán más uniformemente a medida que el número de iteraciones se aproxime al infinito. Si bien esto también es cierto con mt_rand(), en mis pruebas, en promedio, parece ser mucho más rápido para obtener una distribución más pareja. – Gerry

+1

Todo depende de la distribución que sigan los números aleatorios. Es una distribución uniforme, entonces sí. Pero también hay PRNG especializados que generan números aleatorios en otras distribuciones (normal, exponencial, ...), lo que le ahorra el esfuerzo de alterar la distribución (ya que para algunas distribuciones no hay formas fáciles/buenas/eficientes). Cuando se mira desde una sola dimensión, rand() y mt_rand() deberían tener el mismo aspecto en términos de "aleatoriedad". Está comenzando desde 3 dimensiones hacia arriba donde las cosas se divierten con LCGs :-) – Joey

5

escribí una tarea programada que obtiene 1000 números de Random.org periódicamente (por ejemplo, una vez cada hora) y les añade en una matriz de PHP.Cada vez que quiero números aleatorios en mi secuencia de comandos, uso mt_rand (0,1000) para llamar a un número de eso. Algunos microsegundos adicionales de sobrecarga, pero obtengo números verdaderamente aleatorios basados ​​en el ruido atmosférico natural.

+2

Esto introduce la posibilidad de volver a utilizar los mismos números dentro de la matriz antes de que se renueve, que es un conjunto * mucho * más pequeño de valores posibles que el rango completo de enteros de 32 bits, incluso si los mil números provienen del rango más amplio. Un mejor método sería tratar la matriz como una cola; agregando nuevos valores según sea necesario, siempre utilizando el primer elemento y descartándolo después. – gapple

+0

Genere números aleatorios usando los criterios "num = 10000 & min = 1 & max = 1000000" en random.org y obtuve 50 valores duplicados. Entonces parece que no es verdaderamente aleatorio en naturaleza. –

1

uso/dev/ramdom (dispositivo generador aleatorio de números Linux) para sembrar mt_rand

<? 
$rnd_dev=mcrypt_create_iv(4, MCRYPT_DEV_RANDOM); //need "apt-get install php5-mcrypt" 
$seed=ord(substr($rnd_dev, 0, 1))<<24 | 
     ord(substr($rnd_dev, 1, 1))<<16 | 
     ord(substr($rnd_dev, 2, 1))<<8 | 
     ord(substr($rnd_dev, 3, 1)); 
mt_srand($seed); 
echo mt_rand(); 
?> 
+2

Sin una fuente externa de ruido, una computadora no puede tener un "verdadero generador de números aleatorios", y si lo hizo, ¿por qué usarlo para generar una fuente menos aleatoria? Si ya tenía números aleatorios "verdaderos", ¿por qué no usarlos? – Steve

-4

Usando random.org, puede utilizar esto:

function getToken($length, $min, $max){ 
    $r = explode(' 
',file_get_contents('http://www.random.org/integers/num='.$length.'&min='.$min.'&max='.$max.'&col=1&base=10&format=plain')); 

    $string = ''; 
    foreach ($r as $char) $string.=$char; 
    return $string; 
} 

esto debe dar un número real aleatorio

números
+0

Genere números aleatorios usando los criterios "num = 10000 & min = 1 & max = 1000000" en random.org y obtuve 50 valores duplicados. Entonces parece que no es verdaderamente aleatorio en naturaleza. –

-1

Tru azar

<?php 
for ($i = -1; $i <= 4; $i++) { 
    $bytes = openssl_random_pseudo_bytes($i, $cstrong); 
    $hex = bin2hex($bytes); 

    echo "Lengths: Bytes: $i and Hex: " . strlen($hex) . PHP_EOL; 
    var_dump($hex); 
    var_dump($cstrong); 
    echo PHP_EOL; 
} 
?> 

y también crypto secure;)

-2

Aunque la respuesta fue aceptada hace años, voy a volver a abrirla.

Dado que toda esta aleatoriedad depende de la hora del sistema, ¡vamos a meternos también con la hora del sistema! La cantidad de tiempo que una operación toma en la computadora es en realidad bastante variable (especialmente si otras cosas están sucediendo en ese servidor), así que si aprovechamos eso con microtime ... (no pude encontrar ningún comando de nanotime portátil)

$a=''; 
for (int $i=0; $i<9001; $i++) 
{ 
    usleep(mt_rand(1000,10000));//Also eliminates timing attacks... possibly? 
    $a=hash('SHA512',$a.uniqid(mt_rand().microtime(),true)); 
} 
echo $a; 

Nominalmente tiene 207023 bits de entropía, ya que está agregando otros 23 bits en cada iteración, pero hay muchas interdependencias, por lo que probablemente sean unos pocos órdenes de magnitud menor. Aún bastante bueno.

¿Conoces alguna operación en PHP que tome una cantidad de tiempo realmente aleatoria? ¿Te gusta ... HTTP-solicitando algún sitio web (que no sea RANDOM.org) y midiendo el tiempo que toma?

0

I hizo una clase PHP para la generación de números aleatorios y cadenas PHPRandomValue

Se utiliza "mcrypt_create_iv (4, MCRYPT_DEV_URANDOM)" para generar números y valores aleatorios. Lo hice mientras trabajaba en un proyecto de cifrado porque necesitaba un generador de valor aleatorio seguro. He aquí un ejemplo de uso

$randomValue = new RandomValue; 

$randomValue->randomNumber(): = -3880998 

$randomValue->randomNumberBetween(1,10): = 2 

$randomValue->randomTextString(): = CfCkKDHRgUULdGWcSqP4 

$randomValue->randomTextString(10): = LorPIxaeEY 

$randomValue->randomKey(): = C7al8tX9.gqYLf2ImVt/!$NOY79T5sNCT/6Q.$!.6Gf/Q5zpa3 

$randomValue->randomKey(10): = RDV.dc6Ai/ 
22

respuesta rápida:

En un nuevo PHP7 finalmente hay un soporte para un cryptographically secure pseudo-random integers.

int random_int (int $min , int $max) 

También hay un polyfill for PHP5x.

más larga respuesta


No hay generador de números aleatorios perfecto, y los equipos usarán pseudorandom number generator para crear secuencias que se parece al azar. Las secuencias parecen aleatorias (y pasan un poco de randomness tests) pero como hay algún algoritmo para generarlo, puede repetir el algoritmo con absolutamente los mismos estados y obtener el mismo resultado.

El mismo consejo que con cryptography "no invente su propia cifra" se puede traducir a generadores de números aleatorios y significa que no se pueden combinar muchos generadores de números aleatorios y esperar obtener un generador mejor.


Uno de los subgrupos de generadores de números aleatorios es cryptographically secure random number generators:

Los requisitos de un PRNG ordinaria también se cumple mediante una PRNG criptográficamente seguro, pero lo contrario no es cierto. Los requisitos de CSPRNG se dividen en dos grupos: primero, que pasan las pruebas estadísticas de aleatoriedad ; y en segundo lugar, que se sostienen bien bajo seria ataque, incluso cuando parte de su estado inicial o correr se convierte en disponible para un atacante

Así que esto es bastante cerca de su definición de " perfecta". Una vez más sin ninguna condición (excepto para aprender a hacer criptografía) debe intentar implementar uno de esos algoritmos y usarlo en su sistema.


Pero por suerte PHP7 lo tiene implementado,

int random_int (int $min , int $max) 

Genera enteros aleatorios criptográficos que son adecuados para su uso en resultados objetivos son críticos (es decir, arrastrando una baraja de póker).

Las fuentes de azar son los siguientes:

  • En Windows CryptGenRandom() se usa exclusivamente
  • arc4random_buf() se utiliza si está disponible (generalmente específicos BSD)
  • /dev se utiliza/arandom donde esté disponible
  • getrandom(2) la llamada al sistema (en los nuevos núcleos)
  • se utiliza
  • /dev/urandom donde ninguna de las arriba está disponible

Esto hace que todas las respuestas anteriores sean obsoletas (y algunas obsoletas).

+5

Esta es la respuesta ** correcta **. : D –

+0

openssl_random_pseudo_bytes ha estado presente desde 2009/5.3.0 .. sólo se envuelve en algo que comprueba la strong_crypto, por ejemplo, 'función f ($ len) {$ ret = openssl_random_pseudo_bytes ($ len, $ fuerte); if (! $ strong) {throw new \ RuntimeException ('$ crypto_strong failed!');} return $ ret;} ' – hanshenrik

Cuestiones relacionadas