php – 帮我理解pack(),openssl_random_pseudo_bytes()和mt_rand()以获取密码

我正在构建一个具有用户群的应用程序,而我正在确保登录安全.我是编程(和 PHP)的新手,但到目前为止我的努力已经指向使用Crypt()和Blowfish哈希盐.

在我走得更远之前,让我指出我此时对PHPass不感兴趣.

在crypt()文档中,用户最近发布了以下内容

<?PHP 
   $salt = substr(str_replace('+','.',base64_encode(pack('N4',mt_rand(),mt_rand()))),22); 
?>

It is intended for use on systems
where mt_getrandmax() == 2147483647.

The salt created will be 128 bits in
length,padded to 132 bits and then
expressed in 22 base64 characters.
(CRYPT_BLOWFISH only uses 128 bits for
the salt,even though there are 132
bits in 22 base64 characters. If you
examine the CRYPT_BLOWFISH input and
output,you can see that it ignores
the last four bits on input,and sets
them to zero on output.)

Note that the high-order bits of the
four 32-bit dwords returned by
mt_rand() will always be zero (since
mt_getrandmax == 2^31),so only 124 of
the 128 bits will be pseudorandom. I
found that acceptable for my
application.

我测试了我的服务器,确实mt_getrandmax()返回2147483647.我尝试了解文档以了解上面的代码实际上做了什么 – pack()代码N4用于32位字符串(大端字节顺序??)重复4次……我假设这是为什么有4个mt_rand()参数.

我不明白的是他取代的原因.和22 base64字符的目的(不是我完全理解base64是什么.)

建议我查看openssl_random_pseudo_bytes()以获取随机生成,因为我之前看到的方法仅限于1234567890abcdefghijklmnopqrstuvwxyz.

据说5.3.4之前有一个错误导致openssl_random_pseudo_bytes()运行缓慢,偶尔导致超时错误.我不确定是否应该尝试使用带有Crypt()的openssl_random_pseudo_bytes()或者使用mt_rand()和pack()的上述方法.

我试图更多地了解所有这些元素是如何工作的,以及它们在概念上做了什么 – 而不是仅仅使用一个而不理解它来实现我的目标;我正在努力学习:P

有人可以帮助我理解这里工作的不同元素,或者至少将我引导到一个知识库,在那里我可以阅读它吗?我认为最常见的组件是理解不同的格式/术语(base64,ascii,hexdec,bit,byte等),但最后,如何实现一个相当安全的盐用于我的密码.

首先我要说的是,从生成的角度来看,盐没有什么特别之处.这只是另一个随机字符串.它的使用方式很特殊,但没有生成.

你的具体问题

>他为什么要替换.?

我不知道.也许是因为角色可能与网址中的空格混淆.但盐永远不应该在网址中,所以很可能不是.
> base64 / hexdec做什么:

Base64将原始字节流(每个字节的值从0到255)转换为基本64表示.它有很多资源,所以不值得深入研究.阅读the wikipedia article获取更多信息.

hexdec将十六进制数(a-f0-9)转换为十进制数.它从基数16转换为基数10(只是表示数字的另一种方式).
>什么是位和字节:

一点是一个单位的信息.它有2个状态,0或1.字节是一系列8位.所以一个字节可以有256个唯一的组合.阅读Wikipedia
>什么是ascii

这是一个字符集.它表示单个8位字节中的单个可打印字符.我再次建议阅读Wikipedia.

盐一般

良好的盐生成功能的目标是大熵.这意味着可能的输出数量尽可能大.所以任何方法都应该产生大量的结果.

现在,您需要定义salt的可接受字符(因为您需要存储salt以验证哈希值).最好的盐是全字节数字,而不仅仅是可显示的字符.现在,您将无法在有意义的庄园中显示它,但您无需显示它.另外,对于存储,您可以始终使用base64_encode.

接下来,您需要选择盐的浓度.盐越大越好.一个32字符的盐是可以接受的,但128字符的盐更好.盐的大小和每个字符的选项数量将决定存在的可能性的数量.一些常见的组合:

Hex,32 characters: 2e38 possibilities
Hex,128 characters: 1e154 possibilities
Full Byte,32 characters: 1e77 possibilities
Full Byte,128 characters: 1e308 possibilities

现在,您需要生成盐.关键是要根据需要进行多次随机调用以填写熵.你可以通过以下几种方式做到这一点

>系统相关(仅适用于* nix但最佳熵):

$f = fopen('/dev/urandom','r');
$seed = fgets($f,$characters); // note that this will always return full bytes
fclose($f);

>依赖于库(很好,但需要安装OpenSSL)

$seed = openssl_random_pseudo_bytes($characters);

>后备

$seed = '';
for ($i = 0; $i < $characters; $i++) {
    $seed .= chr(mt_rand(0,255));
}

现在,您需要将其转换为所需的输出格式.

>十六进制(a-f0-9):

$out = '';
for ($i = 0,$len = strlen($seed); $i < $len; $i++) {
    $num = ord($seed);
    $out .= dechex(floor($num / 16)) . dechex($num % 16);
}

> Base36(a-z0-9):

$out = '';
for ($i = 0,$len = strlen($seed); $i < $len; $i++) {
    $num = ord($seed);
    $out .= base_convert($num,10,36);
}

> Base64(a-zA-Z0-9 =):

$out = base64_encode($seed);

>完整字节:

没有必要,因为它已经采用这种格式.

相关文章

统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
前言 之前做了微信登录,所以总结一下微信授权登录并获取用户...
FastAdmin是我第一个接触的后台管理系统框架。FastAdmin是一...
之前公司需要一个内部的通讯软件,就叫我做一个。通讯软件嘛...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...