【问题标题】:Generate 4-digit token via php which extends通过扩展的 php 生成 4 位令牌
【发布时间】:2014-02-04 10:00:10
【问题描述】:

您好,这个伟大的社区,

我写了以下几行代码。

mysql_query("DELETE FROM token_db WHERE date < ".strtotime('-1 day'));

$token = mt_rand(1000, 9999);                                                                      
$result = mysql_query("SELECT token FROM token_db WHERE token = $token");

while (mysql_num_rows($result) == 1)
{
$token = mt_rand(1000, 9999);                                                                      
$result = mysql_query("SELECT token FROM token_db WHERE token = $token");
}

mysql_query("INSERT INTO token_db (date,token) VALUES('$date','$token')");

这个脚本生成我最大存在的令牌。 24 小时在数据库中。如果所有令牌(例如 4 位)都在使用中,我如何添加将令牌扩展一位(例如 5 位)的可能性?谢谢!

【问题讨论】:

  • 为了完整性:您的代码容易受到en.wikipedia.org/wiki/SQL_injection的攻击
  • 如果 register_globals 处于关闭状态(应该这样做!!!),这怎么容易受到攻击?用户无法控制任何输入,还是我错了?
  • 您没有展示完整的示例。 $date 可能是个问题,但你通常是对的。
  • 好的。我知道这一点。

标签: php mysql token


【解决方案1】:

您需要对令牌数据库执行计数并计数令牌条目。

 mysql_query("SELECT count(token) FROM token_db");

如果他们达到预定义的限制,例如 9000 或您的 9999,那么只需

 $token = mt_rand(10000, 99999);    

但如果您确实期望更大的数字以避免处理您的情况或多或少常见的场景,我宁愿建议增加您的令牌大小。

您的典型用例是什么?您已经期待更大的尺寸了吗?

无论如何,您的熵很小。使用完整的数据库(比如 9000 个条目),您将很难找到有效的令牌。应用程序将挂起,用户将不得不等待您的脚本敲击数据库。

如果您期望有很多令牌,您可以考虑使用不带日期的令牌预先填充数据库。然后,您可以检索一组未设置日期的随机令牌(LIMIT 1 或 10)并使用它。

您尝试通过此方法实现可扩展性,但我怀疑它是否能正常工作,除非您在数据库仍有 50% 的“空间”时增加令牌数字大小

编辑:另一个问题可能值得一提:您是否通过这样的令牌系统保护任何重要资源?您选择了一个非常小的令牌,已经讨论了令牌冲突,但遗漏的是用户猜测令牌的能力。 如果您通过这种方式保护敏感信息并从 url 读取令牌(例如,您通过邮件将生成的令牌发送给用户等),那么恶意用户可能会通过猜测令牌来冒充另一个用户。 如果您的 4 位数代币用完,这很可能会发生。这就是 uniqid 和其他大型熵算法发挥作用的地方。

【讨论】:

  • +1 表示概念。我认为与简单的uniqid() 相比,这仍然有点矫枉过正,但我​​喜欢替代解决方案
  • 感谢您的冗长回答。预填充数据库以提高速度是个好主意。如果从 1000 到 9999 的所有令牌都在使用,那么数据库又会被 10000 到 99999 填满,对吗?该场景是用户之间通过该令牌进行的轻松通信。为了简单起见,我只想使用数字。如果我减少令牌的生命周期,我会期望更多的令牌,因此自动化很重要。
  • @flix,你可以预先填充它们,但再填充 90000 似乎是一大步。我建议一个离线进程,比如 cron(需要访问 cron 工具,更多信息:stackoverflow.com/questions/18737407/…),它检查数据库中有多少免费令牌,如果少于 100、1000 或任何适合你的,则脚本应生成另一组 100 或 1000 等。您将利用数据库大小并通过此访问新令牌。
  • @flix,我已经编辑了我的帖子并添加了一些关于用户猜测令牌的可能问题。
  • 是的,我也在考虑这个问题。该令牌仅保护一个简单的系统来对 cme​​ts 进行评分,并且直接将其提供给用户(他们在显示器上阅读并输入)。如果我减少令牌的生命周期,我想我会没事的。因此,不良用户必须猜测令牌,并且该令牌应该在特定时间内有效,不良用户会尝试登录。
【解决方案2】:

我猜是这样的:

$result = mysql_query("SELECT count(id) as numRows FROM token_db"); // credit for the edit to Samuel
$fetch = mysql_fetch_assoc($result);
$foundRows = $fetch['numRows'];

$token = $foundRows===(9999-1000) ? mt_rand(10000, 99999) : mt_rand(1000, 9999); 

我添加了大括号以阐明发生了什么,并使用 9999-1000 向您展示了我是如何得到这个数字的(mt_rand 的最大最小值)。如果将其设置为 id 列,因为它们通常是索引、整数和快速 :)

您在此之前进行了测试。

和往常一样:开始使用 mysql*i* 函数


更好、更持久的解决方案是uniqid()

$token = uniqid();

这将永远是一个唯一的 id(惊喜)。不需要检查可能会变得复杂并且没有最大令牌(至少在很长一段时间内不会),

【讨论】:

  • 恕我直言,这是一个糟糕的建议。理论上,您的查询会在您只需要一个数字的情况下获取 9999 个不必要的令牌。改用 mysql 功能并使用count()
  • 我只是在更新它,但感谢您的通知:)
  • 我是第二个 uniqid,因为它降低了冲突的可能性,但无论如何都必须修改这个概念,因为它需要一个字符串类型,它也需要被索引,因为它用于检索(应该是我猜还是在这里完成)
  • 感谢您的回答!当然,使用 uniqid 是完美的,但为了让用户更简单,我只想使用数字。
  • 我仍然认为 uniqid 是要走的路,人们可以复制/粘贴,但否则我推荐 Samuel 的解决方案。从长远来看,它的保护程序和在大型数据集中的速度要快得多
猜你喜欢
  • 1970-01-01
  • 2014-01-21
  • 1970-01-01
  • 1970-01-01
  • 2020-05-22
  • 2019-11-11
  • 2017-06-22
  • 2015-09-23
  • 2019-09-27
相关资源
最近更新 更多