生成加密安全令牌

为了生成一个32个字符的令牌来访问我们的 API,我们目前使用:

$token = md5(uniqid(mt_rand(), true));

我读到过,这种方法在加密上并不安全,因为它是基于系统时钟的,而且 openssl_random_pseudo_bytes会是一个更好的解决方案,因为它更难预测。

如果是这种情况,等价的代码是什么样子的?

我猜是这样的,但我不知道这是否正确..。

$token = md5(openssl_random_pseudo_bytes(32));

还有,我应该传递给函数的长度是多少?

83890 次浏览

If you have a cryptographically secure random number generator, you don't need to hash it's output. In fact you don't want to. Just use

$token  = openssl_random_pseudo_bytes($BYTES,true)

Where $BYTES is however many bytes of data you want. MD5 has a 128bit hash, so 16 bytes will do.

As a side note, none of the functions you call in your original code are cryptographically safe, most are harmful enough that using just one would break be insecure even if combined with secure other functions. MD5 has security issues(though for this application they may not be relevant). Uniqid not just doesn't generate cryptographically random bytes by default (since it uses the system clock), the added entropy you pass in is combined using a linear congruent generator, which is not cryptographically secure. In fact, it probably means one could guess all your API keys given access to a few of them even if they had no idea the value of your server clock. Finally, mt_rand(), what you use as the extra entropy, is not a secure random number generator either.

Here is the correct solution:

$token = bin2hex(openssl_random_pseudo_bytes(16));


# or in php7
$token = bin2hex(random_bytes(16));

If you want to use openssl_random_pseudo_bytes it is best to use CrytoLib's implementation, this will allow you to generate all alphanumeric characters, sticking bin2hex around openssl_random_pseudo_bytes will just result in you getting A-F (caps) and numbers.

Replace path/to/ with where you put the cryptolib.php file (you can find it on GitHub at: https://github.com/IcyApril/CryptoLib)

<?php
require_once('path/to/cryptolib.php');
$token = IcyApril\CryptoLib::randomString(16);
?>

The full CryptoLib documentation is available at: https://cryptolib.ju.je/. It covers a lot of other random methods, cascading encryption and hash generation and validation; but it's there if you need it.

Reliable passwords You can only make from ascii characters a-zA-Z and numbers 0-9. To do that best way is using only cryptographically secure methods, like random_int() or random_bytes() from PHP7. Rest functions as base64_encode() You can use only as support functions to make reliability of string and change it to ASCII characters.

mt_rand() is not secure and is very old. From any string You must use random_int(). From binary string You should use base64_encode() to make binary string reliable or bin2hex, but then You will cut byte only to 16 positions (values). See my implementation of this functions. It uses all languages.

Another option is using RandomLib from ircmaxell (https://github.com/ircmaxell/RandomLib)

Install: composer require ircmaxell/random-lib

Example medium strength

$factory = new Factory();
$factory->getMediumStrengthGenerator()->generateString(32);