使用 php 生成从未使用过的完全唯一的令牌

Generate totally unique token that has never been used using php

所以我想要一种方法来生成身份验证令牌以传递回客户端,以便它可以使用它来传递每个请求。

然而,生成以前从未使用过的唯一令牌的最佳做法是什么。

我需要保证唯一性,所以我不能完全基于 php uniqid() 因为两个用户同时登录的可能性极小(机会很小,但不能冒这个险).

给 uniqid() 值加上用户名前缀是不好的做法吗?

也是 uniqid() 基于的时间戳,当时钟走时容易出现重复值 back/forward?

我猜你已经有了一个数据库来存储这些令牌,这样你就可以检查它是否正确。如果这是真的,你可以按照你喜欢的方式生成令牌(即 uniqid(),随机字符串,......无论你喜欢什么)并检查它是否已经存在于数据库中。如果它不存在,你最好使用它,否则你可以生成一个新的并再次进行检查。

这个方法对我有用...

$token = md5(date['u']);

使用自纪元(1970 年 1 月 1 日)以来的秒数,因此几乎可以保证您获得唯一的一次性值。 MD5 将其转换为 32 个字符的字符串。 2 个相同值的机会仍然不完全为零,但非常接近于零。

使用带 'u' 参数的日期不会因夏令时而成为问题。

您可以使用 UUID,即通用唯一标识符。规格为 rfc4122

节选:

One of the main reasons for using UUIDs is that no centralized authority is required to administer them (although one format uses IEEE 802 node identifiers, others do not). As a result, generation on demand can be completely automated, and used for a variety of purposes. The UUID generation algorithm described here supports very high allocation rates of up to 10 million per second per machine if necessary, so that they could even be used as transaction IDs.

UUID 生成器

有多种语言的 UUID 生成器,只要确保实现使用 RFC-4122 规范中的算法即可。他们中的很多人会简单地为 UUID 的每个十六进制八位字节使用一个随机数,这会导致冲突。

很多都归结为代码可以变得多长,你需要它有多难才能独一无二,它需要多难才能变得不可预测,以及你是否有有效代码列表。

长度

首先:简单的数学意味着如果你必须能够生成无限数量的独特的随机字符串,那么你不能限制所述字符串的长度(它将变得无限...... ).

如果您必须将使用过的值存储在数据库中,通常需要最大长度。

无论如何,无限长度的字符串会产生很多危险。

有多独特?

显然,仅仅使用时间并不是很独特,但您可以添加一些东西来使碰撞的可能性越来越小,同时让预测变得更难。

如果您有一份(当前)有效代码列表,您始终可以根据现有数据库验证生成的代码,并在与当前有效代码发生冲突时重新生成一个新代码。

显然,一个简单的不断增加的计数器将保证唯一性,但它并不方便,因为它不受长度限制,非常可预测等。

难以预测

通常可以猜到的身份验证代码是一个糟糕的安全想法。所以你需要防御它。

全部结合起来

要将它们结合起来,您可以创建一个字符串的串联:

  • 一个固定但秘密的字符串(使其变长)将其视为一个密码短语,这使得猜测您的输入变得非常困难
  • 客户端IP地址
  • 客户端使用的端口号
  • 时间和日期
  • 伪随机数
  • 客户端用来标识自己的字符串
  • 用户名
  • ...

你不需要全部拿走,订单等都由你决定。越多越好

一旦你有了那个字符串,你就可以选择一个散列函数,散列的输出越长,冲突的可能性就越小,但代码在你的数据库中使用的存储空间就越大。

现在一个不错的选择是 sha-1 或 sha-256(md5 有点太破了,不能用于任何新的东西)。

这为您提供了一个长度固定的代码,即使您只更改输入中的一位,也会发生显着变化,攻击者几乎无法预测,并且极有可能导致冲突。

有多小?这是极不可能的,请在此处查看数学:https://crypto.stackexchange.com/questions/24732/probability-of-sha256-collisions-for-certain-amount-of-hashed-values

如果要完全排除这种可能性,又不允许无限长的code,只能对照正在使用的code,如果查到,再生成一个。

TL;DR

除了时间,您还可以添加其他内容,例如连接远程端的 IP 地址、伪随机数、进程 ID、您保密的固定字符串等。将其混合并使用例如sha-256 并且你有一个固定长度的难以预测的代码。

存在碰撞风险,但如果您给它足够的输入来消除它,它会非常小:检查正在使用的代码列表。