Generando una cadena aleatoria REALMENTE en PHP [duplicado]

1

Necesito generar miles (posiblemente millones) de códigos únicos para un cliente. Estos códigos pueden tener un valor monetario, por lo que es vital que sean VERDADERAMENTE aleatorios, y que un hacker inteligente no pueda detectar ni explotar ningún patrón.

He analizado varias soluciones para generar el código (generado cíclicamente = podría suponerse, demasiado arriesgado, uniqid() = bueno, pero es posible que necesite un código de diferente longitud).

Ahora mismo estoy pensando en generar el código usando AZ y 0-9 MINUS VOWELS (para garantizar que no se generen accidentalmente palabras groseras) aunque esto puede aumentar en el futuro a caracteres en minúsculas, etc.

Hasta ahora tengo esto (usando una función rand personalizada tomada de aquí ):

function generateCode($length = 12) {
    $chars = 'BCDFGHJKLMNPQRSTVWXYZ0123456789';
    $count = mb_strlen($chars);

    for ($i = 0, $result = ''; $i < $length; $i++) {
        $randomIndex = devurandom_rand(0, $count - 1);
        $result .= mb_substr($chars, $randomIndex, 1);
    }

    return $result;
}

// CUSTOM RAND FUNCTION
// equiv to rand, mt_rand
// returns int in *closed* interval [$min,$max]                                                
function devurandom_rand($min = 0, $max = 0x7FFFFFFF) {
    $diff = $max - $min;
    if ($diff < 0 || $diff > 0x7FFFFFFF) {
    throw new RuntimeException("Bad range");
    }
    $bytes = mcrypt_create_iv(4, MCRYPT_DEV_URANDOM);
    if ($bytes === false || strlen($bytes) != 4) {
        throw new RuntimeException("Unable to get 4 bytes");
    }
    $ary = unpack("Nint", $bytes);
    $val = $ary['int'] & 0x7FFFFFFF;   // 32-bit safe                           
    $fp = (float) $val / 2147483647.0; // convert to [0,1]                          
    return round($fp * $diff) + $min;
}

Es bastante básico, así que obviamente me preocupa que no sea lo suficientemente aleatorio. ¿Alguien puede decirme si esta es una forma decente de garantizar que el código generado sea verdaderamente aleatorio?

(Nota: Obviamente, un pirata informático aspirante siempre podrá intentar un ataque de fuerza bruta. Estos intentos se manejarán en otro lugar, solo quiero asegurarme de que este código sea verdaderamente aleatorio).

    
pregunta Django Reinhardt 16.11.2013 - 13:38
fuente

1 respuesta

-1

/dev/urandom no es realmente aleatorio, pero una vez que se ha sembrado correctamente, es lo suficientemente bueno para un uso crítico para la seguridad. Para la aleatoriedad true , necesita /dev/random , pero me quedaría con urandom.

Su implementación produce resultados ligeramente sesgados por dos razones:

  1. Los caracteres numéricos (31) no dividen uniformemente 2 ^ 31. Este sesgo es lo suficientemente pequeño como para tener un efecto insignificante en la seguridad. Es posible arreglar esto, pero no me molestaría.
  2. La técnica de redondeo es defectuosa. El primer y último carácter son solo la mitad de probables que el resto.

    Cambiaría lo siguiente:

    $diff = $max - $min + 1;
    
    ...
    
    $fp = (float) $val / 2147483648.0;// 0x80000000, choosing this value ensures that $fp is truly smaller than 1, and not equal
    return floor($fp * $diff) + $min;// now all values 0 <= x <= diff are almost equally likely    
    

Con 12 caracteres, la entropía total es de alrededor de 60 bits. Con un millón de códigos adivinando, incluso uno de ellos debería tomar alrededor de 2 ^ 40, o mil millones de intentos. Esto no es factible para los ataques en línea, donde el atacante necesita enviar una solicitud a su servidor, pero es barato con los ataques sin conexión. Parece que los ataques sin conexión no se aplican a su sistema, por lo que los códigos parecen lo suficientemente grandes.

Suponiendo que tu código php no tenga defectos sutiles, esto debería estar bien. No soy programador de PHP, por lo que podría haberme perdido algo.

En PHP 7 puede usar random_int que es seguro y fácil de usar.

$randomIndex = random_int(0, $count - 1);

En versiones anteriores, puedes usar random_compat biblioteca.

    
respondido por el CodesInChaos 16.11.2013 - 16:07
fuente

Lea otras preguntas en las etiquetas