【问题标题】:How to create unique tokens correctly in php?如何在 php 中正确创建唯一令牌?
【发布时间】:2021-10-06 21:26:27
【问题描述】:

我是 php 新手,我正在自学,通常我创建我的令牌并将它们插入到这样的表格中:

private function create_token($reference, $bytes, $slice)
 {
   $key = substr(preg_replace('/\W/', "", base64_encode(bin2hex(random_bytes($bytes)))), 0, $slice);
   return $reference . $key;
 }

function create_token('token_B8', 34, 22); //token_B8eEr32EEddDsfSDGRGgHHhg

这可能是创建令牌的正确方法,但我怀疑这是否真的是正确的方法,我在想,显然在同一张表中有 2 个令牌并且从 1 到 1000000000 正确吗?或者有没有办法创建一个令牌,上面写着: Under no circumstances create an equal token 无需创建函数来检查表中的令牌是否已存在。

我相信我应该做的是创建一个令牌,我创建它的方式是创建一个函数来检查这个令牌是否已经存在于表中,如果存在,它会生成另一个令牌,如果没有,则将其插入桌子。这似乎是一个正确的方法,但由于我是新手,我不知道是否有更合适的方法,有人可以让我摆脱这个疑问吗?谢谢

【问题讨论】:

  • 为什么要使用 subst、preg_replace 和 base64_encode?为什么不把 bin2hex(random_byres($bytes)) 放在你想要的长度上?
  • 如果 db 表中的该字段被设置为 unique key 时再加上令牌之间发生碰撞的巨大可能性应该足够了......?
  • 我使用 subst 不让我的字符串超过一定长度,使用 preg_replace 替换由于 base64_encode 而不是字母、数字或 '_' 的内容,并使用 base64_encode 使我的令牌资本和小写。
  • @ProfessorAbronsius 我用的是唯一键,但是,唯一键允许表中有唯一值,但是如果已经有值就不插入值了
  • @ProfessorAbronsius 我想知道是否有任何方法可以生成极其独特的令牌,我不知道使用 bin2hex(random_byres($bytes)) 如何生成极其独特的令牌,我想巧合存在,并且可能在我生成一个小时或另一个小时的方式中会出现一个相等的标记

标签: php token


【解决方案1】:

random_bytes() 生成的字符串是最大随机的,从字面上看,你对它所做的一切都会减少字符串中的随机性数量,从而减少它可能的值的数量。

  1. random_bytes() 每字节 8 位随机数。
  2. bin2hex() 将输入的每个字节延伸到两个字节。 [x0.5]
  3. base64_encode() 将 3 个输入字节延伸到 4 个输出字节。 [x0.75]
  4. preg_replace('/\W/', "", $input) 有效地从 base64 编码更改为 base62,再次略微减少了空间。 [X???

总而言之,您生成的 22 字节令牌代表 22 * 8 * 0.5 * 0.75 * ??? <= 66 位随机数据​​。所以

男孩,你好,这肯定看起来很多,对吧?不是真的。由于Birthday Paradox,碰撞概率可能会进入导致问题的范围,而您距离填充范围还有几个数量级。

我想如果我们删除那个毫无意义的bin2hex(),我们可以挤出另外 66 位总共 132 位吗?但是,这真的能带给我们多少?

5,444,517,870,735,015,415,413,993,718,908,291,383,296

很多。 很多。我什至不再关心preg_replace()

为了完整起见,只是一个random_bytes(22) 怎么样? 176 位?

95,780,971,304,118,053,647,396,689,196,894,323,976,171,195,136,475,136

我猜的要点是:

  1. 不要仅仅因为输出看起来乱码就将数据编码与“使更多随机”混淆。 [注意:哈希函数也是如此]
  2. 如果您不知道函数/编码实际在做什么,请不要随意应用它们。

在代码中:

$input = 'abc';

// all of these outputs contain the SAME amount of entropy, some of them are just longer representations
var_dump(
    $input,
    bin2hex($input),
    base64_encode($input),
    base64_encode(bin2hex($input)),
    bin2hex(base64_encode($input))
);

输出:

string(3) "abc"
string(6) "616263"
string(4) "YWJj"
string(8) "NjE2MjYz"
string(8) "59574a6a"

无论如何,对于足够大的随机 ID 空间,只对值设置 UNIQUE 约束并在尝试插入重复值时让进程失败更为实用。你可以加入一些重试逻辑,但很可能它永远不会真正运行,除非有人专门利用漏洞make你自己生成重复和 DoS 重试。 [是的,这是一件事]

【讨论】:

  • 太棒了,我什至加热了一杯巧克力牛奶来阅读这个精彩的答案,我对生日悖论一无所知,谢谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-12
  • 2021-11-13
  • 2015-02-04
  • 2018-09-15
  • 2014-03-31
  • 2018-11-25
  • 1970-01-01
相关资源
最近更新 更多