Generazione di una stringa casuale VERAMENTE in PHP [duplicato]

1

Ho bisogno di generare migliaia (possibilmente milioni) di codici univoci per un cliente. Questi codici possono avere un valore monetario, quindi è vitale che siano VERAMENTE casuali e che nessun modello possa essere individuato e sfruttato da un hacker intelligente.

Ho esaminato varie soluzioni per generare il codice (generato ciclicamente = potrebbe essere indovinato, troppo rischioso, uniqid() = buono, ma potrei aver bisogno di un codice di lunghezza diversa).

In questo momento sto pensando di generare il codice usando AZ e 0-9 MINUS VOWELS (al fine di garantire che non vengano generate accidentalmente parole maleducate) anche se questo potrebbe essere aumentato in futuro a caratteri minuscoli, ecc.

Finora ho questo (usando una funzione rand personalizzata tratta da qui ):

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;
}

È piuttosto semplice, quindi sono ovviamente preoccupato che non sia abbastanza casuale. Qualcuno può dirmi se questo è un modo decente per garantire che il codice generato sia veramente casuale?

(Nota: ovviamente un hacker di prestigio sarà sempre in grado di tentare un attacco di forza bruta.Tali tentativi saranno gestiti altrove, voglio solo assicurarmi che questo codice sia veramente casuale.)

    
posta Django Reinhardt 16.11.2013 - 13:38
fonte

1 risposta

-1

/dev/urandom non è veramente casuale, ma una volta che è stato seminato correttamente è abbastanza buono per un utilizzo critico della sicurezza. Per la vera casualità, hai bisogno di /dev/random , ma rimango con urandom.

La tua implementazione produce un output leggermente distorto per due motivi:

  1. I caratteri numerici (31) non dividono equamente 2 ^ 31. Questo errore è abbastanza piccolo da avere un effetto trascurabile sulla sicurezza. È possibile risolvere questo problema, ma non mi preoccuperei.
  2. La tecnica di arrotondamento è difettosa. Il primo e l'ultimo carattere hanno solo la metà delle probabilità del resto.

    Io cambierei quanto segue:

    $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 caratteri l'entropia totale è di circa 60 bit. Con un milione di codici che indovina anche uno di loro dovrebbe prendere circa 2 ^ 40 o mille miliardi di tentativi. Questo è impossibile per gli attacchi online, in cui l'autore dell'attacco deve inviare una richiesta al server, ma è economico con attacchi offline. Sembra che gli attacchi offline non si applichino al tuo sistema, quindi i codici sembrano abbastanza grandi.

Supponendo che il tuo codice php non abbia difetti sottili, dovrebbe andare bene. Non sono programmatore di php, quindi potrei aver perso qualcosa.

In PHP 7 puoi usare random_int che è sicuro e facile da usare.

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

Nelle versioni precedenti potresti utilizzare random_compat biblioteca.

    
risposta data 16.11.2013 - 16:07
fonte

Leggi altre domande sui tag