¿Es seguro este RNG de PHP?

0

Necesito generar una cadena aleatoria de 20 caracteres sin ninguna vocal, y hasta ahora tengo la siguiente función para llevar a cabo la tarea.

function random_str()
{
    $i = 1;
    $secret = '';

    while($i==1){
        $str = bin2hex(random_bytes(10));

        $str = preg_replace('/[aeiouAEIOU]|\W+/', '', sha1(microtime() . mt_rand() . $str ));
        $secret .= $str;
        if(strlen($secret) >= 20){
            $i = 0;
        }
    }

    return substr($secret, 0, 20);
}

¿Esto es seguro? ¿Hay alguna manera de mejorarlo?

Esto no se usa en nada en vivo hasta el momento, pero se usará para generar claves para restablecer las contraseñas y para ver ciertas partes de un sistema que normalmente requiere que un usuario inicie sesión.

    
pregunta AntlerFox 08.02.2017 - 11:18
fuente

1 respuesta

2

Una limpieza de tu código

Esto es lo mismo que estás haciendo, pero escrito un poco más elegante:

function random_str()
{
    $secret = '';
    while(strlen($secret) >= 20) {
       $str = bin2hex(random_bytes(10));
       $str = preg_replace('/[aeiouAEIOU]|\W+/', '', sha1(microtime() . mt_rand() . $str));
       $secret .= $str;
    }
    return substr($secret, 0, 20);
}

Note que he eliminado la variable innecesaria $i . (Lo sé, no es un problema de seguridad, pero de todos modos).

¿Es seguro?

El código es muy complicado, y toma un camino bastante extraño para resolver un problema no tan difícil. Algunos problemas:

  • Usas el hash sha1(microtime() . mt_rand() . $str) cuando solo basándote en $str sería suficiente. Ahí es donde se obtiene la entrada de un CSPRNG. Agregar algo de aleatoriedad no segura ( mt_rand ) y el tiempo y luego modificarla no la mejora.
  • Como eliminas las vocales de una cadena hexadecimal, terminas usando solo el carácter 0123456789bcdf . Eso es solo catorce, no mucho.
  • Es un poco extraño generar primero una cadena que contenga los caracteres que no quieres y luego tirarlos, cuando solo podrías generar los que quieres.

Al final, el resultado es criptográficamente seguro, ya que se basa en random_bytes() , eso es un CSPRNG. Pero las peculiaridades de su código y su falta de comprensión lo llevan a la inseguridad, por ejemplo. en este caso, podría terminar con menos entropía por personaje de lo que hubiera esperado.

Una mejor manera de hacerlo

Use la función PHP random_int para elegir un personaje de un alfabeto fijo al azar :

function random_string($length, $alphabet) {
    $result = ''; //Initialize an empty string.
    $max = strlen($alphabet) - 1; //The maximum random number we want to generate.
    for($i = 0; $i < $length; $i++) { //Do once for every character in the string.
        $result .= $alphabet[random_int(0, $max)]; //Add a random letter from the alphabet.
    }
    return $result;
}

El rendimiento probablemente podría mejorarse eliminando la concatenación de cadenas en el bucle, pero probablemente no sea un gran problema.

    
respondido por el Anders 08.02.2017 - 12:51
fuente

Lea otras preguntas en las etiquetas