2010-04-07 26 views
30

Quiero crear un generador de tokens que genere tokens que el usuario no pueda adivinar y que sigan siendo únicos (para ser utilizados para el restablecimiento de contraseñas y los códigos de confirmación).md5 (uniqid) tiene sentido para tokens únicos aleatorios?

A menudo veo este código; ¿tiene sentido?

md5(uniqid(rand(), true)); 

según un commentuniqid($prefix, $moreEntopy = true) rendimientos

primeros 8 caracteres hexadecimales = unixtime, últimos 5 hexagonales chars = microsegundos.

No sé cómo se maneja el $prefix -parámetro ..

lo tanto, si no se establece la bandera $ moreEntopy de verdad, da un resultado predecible.


PREGUNTA:Pero si usamos uniqid con $moreEntopy, lo que no hash MD5 con nosotros comprar? ¿Es mejor que:

md5(mt_rand()) 

edit1: pueda almacenar este token en una columna de base de datos con un índice único, así que detectará columnas. Puede ser de interés/

Respuesta

43

rand() es un riesgo de seguridad y nunca se debe usar para generar un token de seguridad: rand() vs mt_rand() (Mire las imágenes "estáticas"). Pero ninguno de estos métodos para generar números aleatorios es criptográficamente seguro. Para generar datos seguros, una aplicación necesitará acceder a CSPRNG provisto por la plataforma, el sistema operativo o el módulo de hardware.

En una aplicación web, una buena fuente de secretos seguros es el acceso no bloqueante a un conjunto de entropía como /dev/urandom.A partir de PHP 5.3, las aplicaciones PHP pueden usar openssl_random_pseudo_bytes(), y la biblioteca Openssl elegirá la mejor fuente de entropía según su sistema operativo, en Linux esto significa que la aplicación utilizará /dev/urandom. Este code snip from Scott is pretty good:

function crypto_rand_secure($min, $max) { 
     $range = $max - $min; 
     if ($range < 0) return $min; // not so random... 
     $log = log($range, 2); 
     $bytes = (int) ($log/8) + 1; // length in bytes 
     $bits = (int) $log + 1; // length in bits 
     $filter = (int) (1 << $bits) - 1; // set all lower bits to 1 
     do { 
      $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes))); 
      $rnd = $rnd & $filter; // discard irrelevant bits 
     } while ($rnd >= $range); 
     return $min + $rnd; 
} 

function getToken($length=32){ 
    $token = ""; 
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz"; 
    $codeAlphabet.= ""; 
    for($i=0;$i<$length;$i++){ 
     $token .= $codeAlphabet[crypto_rand_secure(0,strlen($codeAlphabet))]; 
    } 
    return $token; 
} 
+1

'md5() en este caso se utiliza para oscurecer el momento en que se creó, que es un uso legítimo' Eso suena como la respuesta. –

+0

tengo un proceso de servidor que necesita tomar datos de formulario y guardarlo como uniquetoken.xml. Ya tengo el formulario listo para crear el archivo xml. Hasta ahora los estoy nombrando con cada mmddyy.xml. ¿Cómo podría reemplazarlo con md5 (uniqid (mt_rand(), true));? – marciokoko

+0

Esto es inseguro. Consulte la respuesta de Scott. – ChocoDeveloper

-1

MD5 es un algoritmo decente para producir ID dependientes de datos. Pero en caso de que tenga más de un elemento que tenga el mismo flujo de bits (contenido), estará produciendo dos ID "MD5" similares.

Si solo lo está aplicando a una función rand(), que garantiza que no se creará el mismo número dos veces, estará completamente seguro.

Pero para una distribución más fuerte de las claves, yo personalmente usaría SHA1 o SHAx etc. '... pero aún tendrá el problema de que datos similares conducen a claves similares.

+0

Publicación antigua, pero ¿cómo se garantiza 'rand()' no crear el mismo número dos veces? – JSmyth

1

Definir "único". Si quiere decir que dos tokens no pueden tener el mismo valor, el hashing no es suficiente: debe respaldarse con una prueba de exclusividad. El hecho de que suministre el algoritmo hash con entradas únicas no garantiza salidas únicas.

+0

unique = no tiene el mismo valor de hecho. Cada token está asociado con una dirección de correo electrónico única. Tal vez podríamos usar esto para hacer un token aleatorio único. Todavía no estoy seguro de cuál es la mejor manera de hacer esto. –

1

Para responder a su pregunta, el problema es que no puede tener un generador que está garantizado al azar y único como aleatorio por sí mismo, es decir, md5(mt_rand()) puede dar lugar a duplicados. Lo que quiere es valores únicos de "aparición aleatoria". uniqid proporciona la identificación única, rand() afijos un número aleatorio que hace que sea aún más difícil de adivinar, md5 enmascara el resultado para hacerlo aún más difícil de adivinar. Nada es indescifrable Solo tenemos que hacerlo tan difícil que ni siquiera querrían intentarlo.

+1

Usted dice "md5 enmascara el resultado para hacerlo aún más difícil de adivinar". Entonces uniqueid genera un resultado algo aleatorio que es único. ¿Qué quiere decir precisamente con enmascarar? Si quisiera seguir este pensamiento, 'md5 (md5 (uniqid (rand(), true)' significaría aún más enmascaramiento, pero es peor ¿no? –

+0

@Excpetion e, un hash doble md5() no mejora la seguridad de este sistema. – rook

1

me encontré con una idea interesante hace un par de años.
Almacenando dos valores hash en la base de datos, uno generado con md5 ($ a) y el otro con sha ($ a). Luego chek si ambos valores son corect. El punto es que si el atacante rompió tu md5(), no puede romper tu md5 AND sha en el futuro cercano.
El problema es: ¿cómo se puede usar ese concepto con la generación de tokens necesaria para su problema?

+0

¿No bastaría con combinarlos con un pegamento de cadena como _ o - para crear una ficha combinada que sería mucho más improbable que tenga una colusión? No necesita mantenerlos en campos de db separados. Puedes mantenerlos como fusionados. Y si necesita hacer alguna operación con ellos, puede procesar la cadena con una función. De esta forma, la cadena combinada se puede usar como un token para cualquier cadena única que requiera un proceso, como las claves de sesión o las solicitudes de restablecimiento de contraseña u otras muchas cosas. – unity100

21

Esta es una copia de otra pregunta que encontré que se le preguntó unos meses antes de esta. Aquí hay un enlace a la pregunta y mi respuesta: https://stackoverflow.com/a/13733588/1698153.

No estoy de acuerdo con la respuesta aceptada. De acuerdo con el propio sitio web de PHP "[uniqid] does not generate cryptographically secure tokens, in fact without being passed any additional parameters the return value is little different from microtime(). If you need to generate cryptographically secure tokens use openssl_random_pseudo_bytes()."

No creo que la respuesta sea más clara que esto, uniqidno es seguro.

+0

Esta debería ser la respuesta aceptada. – ChocoDeveloper

+0

upvoted para que la gente realmente compruebe el enlace en lugar de la respuesta aceptada. – perlwle

+1

Scott, no estaba al tanto de esa pregunta anterior, sry. Supongo que 'openssl_random_pseudo_bytes()' (PHP 5> = php 5.3) no siempre estaba disponible en el momento de hacer la pregunta. Tiene razón, la respuesta aceptada ha cambiado y se refiere a su respuesta en este momento, para que otras personas no se equivoquen. –

3

Sé que la pregunta es antiguo, pero aparece en Google, así que ...

Como otros han dicho, rand(), mt_rand() o uniqid() no le garantiza la unicidad ... incluso openssl_random_pseudo_bytes() no debe utilizarse , ya que usa deprecated features of OpenSSL.

Lo que debe usar para generar hash aleatorio (igual que md5) es random_bytes() (introducido en PHP7). Para generar hash con misma longitud que MD5:

bin2hex(random_bytes(16));

Si está usando PHP 5.x usted puede conseguir esta función mediante la inclusión de random_compat library.

+0

¡Válida respuesta! Su preocupación con respecto a 'openssl_random_pseudo_bytes()' parece haberse arreglado https://bugs.php.net/bug.php?id=70014. –

Cuestiones relacionadas