por generate autenticacion php security random timestamp token

generate - autenticacion por token php



la mejor práctica para generar token aleatorio para contraseña olvidada (6)

Quiero generar identificador para contraseña olvidada. He leído que puedo hacerlo usando la marca de tiempo con mt_rand (), pero algunas personas dicen que la marca de tiempo puede no ser única cada vez. Así que estoy un poco confundido aquí. ¿Puedo hacerlo usando la marca de tiempo con esto?

Pregunta
¿Cuál es la mejor práctica para generar tokens aleatorios / únicos de longitud personalizada?

Sé que hay muchas preguntas por aquí, pero cada vez me siento más confundido después de leer opiniones diferentes de las diferentes personas.


Esto puede ser útil siempre que necesite un token muy muy aleatorio

<?php echo mb_strtoupper(strval(bin2hex(openssl_random_pseudo_bytes(16)))); ?>


La versión anterior de la respuesta aceptada ( md5(uniqid(mt_rand(), true)) ) es insegura y solo ofrece alrededor de 2 ^ 60 resultados posibles, dentro del rango de una búsqueda de fuerza bruta en aproximadamente una semana por un bajo -Auditor de presupuesto:

Como una clave DES de 56 bits puede ser forzada por fuerza bruta en aproximadamente 24 horas , y una caja promedio tendría aproximadamente 59 bits de entropía, podemos calcular 2 ^ 59/2 ^ 56 = aproximadamente 8 días. Dependiendo de cómo se implemente esta verificación de token, es posible que prácticamente se pierda información de temporización e inferir los primeros N bytes de un token de restablecimiento válido .

Dado que la pregunta es sobre "mejores prácticas" y se abre con ...

Quiero generar identificador para contraseña olvidada

... podemos inferir que este token tiene requisitos de seguridad implícitos. Y cuando agrega requisitos de seguridad a un generador de números aleatorios, la mejor práctica es usar siempre un generador de números pseudoaleatorios criptográficamente seguro (abreviado CSPRNG).

Usando un CSPRNG

En PHP 7, puede usar bin2hex(random_bytes($n)) (donde $n es un entero mayor que 15).

En PHP 5, puedes usar random_compat para exponer la misma API.

Alternativamente, bin2hex(mcrypt_create_iv($n, MCRYPT_DEV_URANDOM)) si tiene ext/mcrypt instalado. Otro buen one-liner es bin2hex(openssl_random_pseudo_bytes($n)) .

Separación de la búsqueda del Validador

Extracto de mi trabajo previo sobre cookies seguras de "recordarme" en PHP , la única manera efectiva de mitigar la pérdida de tiempo antes mencionada (generalmente introducida por la consulta de la base de datos) es separar la búsqueda de la validación.

Si su tabla se ve así (MySQL) ...

CREATE TABLE account_recovery ( id INTEGER(11) UNSIGNED NOT NULL AUTO_INCREMENT userid INTEGER(11) UNSIGNED NOT NULL, token CHAR(64), expires DATETIME, PRIMARY KEY(id) );

... debe agregar una columna más, selector , como ese:

CREATE TABLE account_recovery ( id INTEGER(11) UNSIGNED NOT NULL AUTO_INCREMENT userid INTEGER(11) UNSIGNED NOT NULL, selector CHAR(16), token CHAR(64), expires DATETIME, PRIMARY KEY(id), KEY(selector) );

Usar un CSPRNG Cuando se emite un token de restablecimiento de contraseña, envíe ambos valores al usuario, almacene el selector y un hash SHA-256 del token aleatorio en la base de datos. Use el selector para tomar el hash y la ID de usuario, calcule el hash SHA-256 del token que el usuario proporciona con el almacenado en la base de datos usando hash_equals() .

Código de ejemplo

Generar un token de reinicio en PHP 7 (o 5.6 con random_compat) con PDO:

$selector = bin2hex(random_bytes(8)); $token = random_bytes(32); $urlToEmail = ''http://example.com/reset.php?''.http_build_query([ ''selector'' => $selector, ''validator'' => bin2hex($token) ]); $expires = new DateTime(''NOW''); $expires->add(new DateInterval(''PT01H'')); // 1 hour $stmt = $pdo->prepare("INSERT INTO account_recovery (userid, selector, token, expires) VALUES (:userid, :selector, :token, :expires);"); $stmt->execute([ ''userid'' => $userId, // define this elsewhere! ''selector'' => $selector, ''token'' => hash(''sha256'', $token), ''expires'' => $expires->format(''Y-m-d/TH:i:s'') ]);

Verificación del token de restablecimiento proporcionado por el usuario:

$stmt = $pdo->prepare("SELECT * FROM account_recovery WHERE selector = ? AND expires >= NOW()"); $stmt->execute([$selector]); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); if (!empty($results)) { $calc = hash(''sha256'', hex2bin($validator)); if (hash_equals($calc, $results[0][''token''])) { // The reset token is valid. Authenticate the user. } // Remove the token from the DB regardless of success or failure. }

Estos fragmentos de código no son soluciones completas (evité la validación de entrada y las integraciones de framework), pero deberían servir como un ejemplo de qué hacer.


Puede usar echo str_shuffle (''ASGDHFfdgfdre5475433fd'');


También puede usar DEV_RANDOM, donde 128 = 1/2 la longitud del token generado. El siguiente código genera 256 tokens.

$token = bin2hex(mcrypt_create_iv(128, MCRYPT_DEV_RANDOM));



En PHP, use random_bytes() . Motivo: está buscando la forma de obtener un token de recordatorio de contraseña y, si es una credencial de inicio de sesión por única vez, entonces realmente tiene que proteger los datos (que es - cuenta de usuario completa)

Entonces, el código será el siguiente:

//$length = 78 etc $token = bin2hex(random_bytes($length));

Actualización : las versiones anteriores de esta respuesta se referían a uniqid() y eso es incorrecto si hay una cuestión de seguridad y no solo unicidad. uniqid() es esencialmente solo microtime() con alguna codificación. Hay formas simples de obtener predicciones precisas de la microtime() en su servidor. Un atacante puede emitir una solicitud de restablecimiento de contraseña y luego probar un par de posibles tokens. Esto también es posible si se utiliza more_entropy, ya que la entropía adicional es similarmente débil. Gracias a @NikiC y por señalar esto.

Para más detalles ver