Nasıl PHP ile şifreli olarak güvenli rasgele numaralar oluşturur?

5 Cevap php

Possible Duplicate:
Secure random number generation in PHP

Biz veritabanı oturum verilerine bağlı olacak bir kimlik doğrulama belirteci olarak kullanmak için bir şifreli rasgele dize oluşturmak gerekiyor. Biz uygun bir rasgele sayı üreteci yerleşik olması görünmüyor PHP, kullanıyor. Nasıl php kullanarak N uzunluğunda bir şifreli olarak güvenli rasgele bir dize oluşturabilir?

Ayrıca nedeniyle bizim uygulamanın doğası gereği, dikkat, shell_exec masadan olduğunu.

5 Cevap

Platforma bağlı olarak, / dev / urandom veya CAPICOM kullanabilirsiniz. Bu güzel özetlenmiştir this comment from Mark Seecof:

Güvenlik ve şifreleme amaçlı bazı pseudorandom bit (yumurta, blok şifreleme için rasgele IV, parola karma için rastgele tuz) mt_rand () kötü bir kaynağıdır. Gerekiyorsa "en Unix / Linux ve / veya MS-Windows platformlarında alabilirsiniz Bu gibi işletim veya sistem kütüphaneden pseudorandom bit daha iyi bir notu:

<?php
// get 128 pseudorandom bits in a string of 16 bytes

$pr_bits = '';

// Unix/Linux platform?
$fp = @fopen('/dev/urandom','rb');
if ($fp !== FALSE) {
    $pr_bits .= @fread($fp,16);
    @fclose($fp);
}

// MS-Windows platform?
if (@class_exists('COM')) {
    // http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx
    try {
        $CAPI_Util = new COM('CAPICOM.Utilities.1');
        $pr_bits .= $CAPI_Util->GetRandom(16,0);

        // if we ask for binary data PHP munges it, so we
        // request base64 return value.  We squeeze out the
        // redundancy and useless ==CRLF by hashing...
        if ($pr_bits) { $pr_bits = md5($pr_bits,TRUE); }
    } catch (Exception $ex) {
        // echo 'Exception: ' . $ex->getMessage();
    }
}

if (strlen($pr_bits) < 16) {
    // do something to warn system owner that
    // pseudorandom generator is missing
}
?>

NB: Her Kullanıcının diğer platform üzerinde sessizce başarısız olsa, / dev / urandom okuma girişimi ve kodunuzda CAPICOM erişmek için girişimi hem de bırakmak genellikle güvenlidir. Kodunuzu daha taşınabilir olacak şekilde orada ikisini de bırakın. "

Diğer yanıtlara dayanarak, ben oldukça güvenli numaraları ve güvensiz mt_rand yerine tekrarlanabilir dizileri hem de üreten bir sınıf tasarlama özgürlük aldı.

Bu sınıf Ben internet ve ben kendi rasgele sayı üreteci haddeleme için bulunan bir öğretici bir yerde bulunan srp_hermetic paketi ile gelen fonksiyonlar dayanmaktadır.

class cryptoLibException extends Exception{};
class noSupportedBigMathLibraryException extends Exception{};
class noSupportedRandomSourceException extends Exception{};


class cryptoLib{

#random seed
private static $RSeed = 0;

public static function isHex( $input = '' ){
    for($i=0; $i<strlen( $input ); $i++){
        $digit  = ord( $input[$i] );
        if( $digit < 48 || $digit > 102 ){ return false; }
        if( $digit < 96 && $digit > 57  ){ return false; }
    }
    return true;
}

public static function hex2dec($hex = ''){
    if( !self::isHex( $hex ) ){
        throw new cryptoLibException();
        return false;
    }
    if( function_exists( 'bcmul' ) && function_exists( 'bcadd' ) ){
        $dec    = '0';
        $pow    = '1';
        for( $i = strlen( $hex ) - 1; $i >= 0; $i--){
            $digit  = ord( $hex[$i] );
            $digit  = ( ( $digit>96 )? ( $digit ^ 96 ) + 9: $digit ^ 48 );
            $dec    = bcadd( $dec, bcmul( $pow, $digit ) );
            $pow    = bcmul( $pow, '16' );
        }
        return $dec;
    }else if( function_exists( 'gmp_init' ) && function_exists( 'gmp_strval' ) ){
        $hex = gmp_init(   $hex, 16 );
        return gmp_strval( $hex, 10 );
    }else{
        throw new noSupportedBigMathLibraryException();
    }
    return false;
}

public static function dec2hex($dec = ''){
    if( function_exists( 'bcmod' ) && function_exists( 'bcdiv' ) && function_exists( 'bccomp' ) ){
        $digits = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
        $hex = '';
        do{
            $digit  = bcmod( $dec, '16' );
            $dec    = bcdiv( $dec, '16' );
            $hex    = $digits[$digit].$hex;
        }while( bccomp( $dec, '0' ) );
        return $hex;
    }else if( function_exists( 'gmp_init' ) && function_exists( 'gmp_strval' ) ){
        $hex = gmp_init(   $dec, 10 );
        return gmp_strval( $dec, 16 );
    }else{
        throw new noSupportedBigMathLibraryException();
    }
    return false;
}

public static function byte2hex($bytes = ''){
    $digits = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
    $hex    = '';
    $len    = strlen( $bytes );
    for( $i = 0; $i < $len; $i++ ){
        $b      = ord( $bytes[$i] ) & 0xFF;
        $hex    = $hex . $digits[( $b & 0xF0 ) >> 4];
        $hex    = $hex . $digits[$b & 0x0F];
    }
    return $hex;
}

public static function secure_random($bits = 16){

    $bytes = $bits/8;
    $result = '';
    $digits = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');

    $pr_bits    = '';

    #Unix/Linux platform
    $fp         = @fopen( '/dev/urandom', 'rb' );
    if( $fp !== false ){
        $pr_bits    .= @fread( $fp, $bytes );
        @fclose( $fp );
    }

    #MS-Windows platform before CAPICOM discontinued
    if( @class_exists( 'COM' ) ){
        #http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx
        try{
            $CAPI_Util  = new COM( 'CAPICOM.Utilities.1' );
            $pr_bits    .= $CAPI_Util->GetRandom( $bytes, 0 );

            #ask for binary data PHP munges it, so we 
            #request base64 return value.  We squeeze out the 
            #redundancy and useless ==CRLF by hashing... 
            if( $pr_bits ){ $pr_bits    = md5( $pr_bits, true ); }
        }catch(Exception $e){} 
    } 

    #nothing has worked yet so lets make an outside connection
    if( strlen( $pr_bits ) < $bytes ){
        try{
            $pr_bits = file_get_contents( "http://www.random.org/cgi-bin/randbyte?nbytes=$bytes&format=h" ); #connect to random.org for the random stuff
            $pr_bits = preg_replace( '/[^0-9A-z]/', '', trim( $pr_bits ) ); #git rid of the spaces, only leaves the 16 bits or 32 characters
            $pr_bits = pack( "H*", $pr_bits ); #pack it down into the 16 byte string
        }catch(Exception $e){}
    }

    #failed to get any random source to work
    if( strlen( $pr_bits ) < $bytes ){
        throw new noSupportedRandomSourceException();
        return false;
    }


    $len = strlen($pr_bits);
    $b = 0;

    for( $i = 0; $i < $len; $i++ ){
        $b      = ord( $pr_bits[$i] );
        $result = $result . $digits[ ($b & 0xF0) >> 4 ];
        $result = $result . $digits[$b & 0x0F];
    }
    return $result;
}

#set random seed
public static function seed($s = 0){
    self::$RSeed = abs(intval($s)) % 9999999 + 1;
    self::s_rand();
}

#replaces php native random functions
#efficent, uses secure seeding and repeatable sequencing if the same seed is provided
public static function s_rand($min = 0, $max = 9999999){
    if (self::$RSeed == 0) self::seed(self::hex2dec(self::secure_random()));
    self::$RSeed = (self::$RSeed * 125) % 2796203;
    return self::$RSeed % ($max - $min + 1) + $min;
}

}

Kafamın üst kapalı:, mikro zaman microtime% 100 ile çarpın ve alınan sonuç sha1 üzerine birkaç randoms yapın.

Ben gerçekten oturum işleme için şifreli olarak güvenli rasgele sayı gerek olmadığını düşünüyorum. Eğer ihtiyacınız kadar rasgele semboller almak için for döngü içinde yerleşik rand() işlevini kullanabilirsiniz. Ya da sadece ol sopa 'güvenilir md5($salt.time().rand(10000).microtime())