使用PHP和MySQL生成强大且唯一的用户ID

5

嘿,Stack Overflow!这是我的第一篇帖子...

我正在尝试使用加盐的唯一公钥来识别用户。

  1. 算法 - 我应该使用uniqid()、sha256、sha512或其他什么?所有哈希值都将被加盐。NIST推荐使用SHA256,但我更愿意听听其他人的建议。
  2. 生成 - 使用hash(SALT + AUTO_INCREMENT_PK + CREATED_TIMESTAMP)足够吗?需要更多的熵吗?
    • 我会使用电子邮件,因为它对于每个用户来说是唯一的,但用户可以修改他们的电子邮件地址。我还考虑存储signup_email,以便无需重新计算哈希值。
  3. MySQL存储 - 目前,我们的ID是INT(255) auto_increment主键。如前所述,可能有数亿个密钥。根据加密算法,我应该有一个固定大小的ID。我可以保留INT(255),还是应该使用CHAR(n)?

---------------------- 感谢阅读 :) -------------------------------


我猜一个补充目标是:这种系统的整体速度是否比使用增量整数更快,而且为了获得额外的安全性是否值得牺牲速度?我想问一下,INT能否有效地存储十六进制?根据威尔的建议,我想尝试使用sha256。 - brack
5个回答

5

一件事情:如果你不信任用户的ID,那么通过GET或POST发送它们将无法起作用;这些都对有动机的用户可见。


我会使用一个盐.计数器.时间字符串来使用SHA256,并使用输出为实际id生成GUID。这将最小化冲突的可能性。

您必须使用MySQL的CHAR来存储GUID。

有关更详细的信息,请参见http://us2.php.net/manual/en/function.uniqid.php上的评论。据我所知,GUID不是PHP核心的一部分,因此您需要进行一些伪造。


散列并非必要的。实际上,哈希函数并不会创建唯一值。 - Gumbo
@Gumbo - 严格来说不是,但使用像Rijndal这样的高质量哈希函数,并配以高质量熵输入,可以生成具有接近零的天文数字低冲突率的哈希值。 - willoller
这基本上回答了我的问题,因为我想知道是否需要char还是可以保留INT。正如Will所提到的,天文数字的低碰撞几率对我来说没关系,因为我认为我会有足够的熵。我也会研究salt.counter.time。如果我在保持低碰撞率的同时生成哈希值,是否仍然可以使用MySQL的INT(255)作为数据类型? - brack
你可以将GUID存储在查找表中,或者使用INT作为主键并将GUID保存在第二列中。这样做可能会提高性能,因为您将使用INT来执行JOIN和INDEX操作,但我不确定。 - willoller
是的,我的用户表目前使用递增的INT作为主键,并且我打算添加另一个UID列。也许我仍然应该始终将用户ID在数据库中引用为int,只有在公开时才使用UID。 - brack
1
@willoller:使用真实的UID函数将使您的碰撞概率为零。 - Gumbo

3
如果您使用用户ID作为允许用户使用您的服务的方式,如果一个用户“猜测”另一个用户的用户ID,他将能够随意操作该用户的帐户?
您没有任何其他密码或类似的东西吗?
那么,在这种情况下,您需要一些非常独特的东西,不是吗 ;-)
(希望我理解了问题 - 但可能不是这种情况 - 如果不是,很抱歉)
您认为使用{{link1:全局唯一标识符}}(例如,61350955-9755-4AF3-8C19-6DBC42CA69E2)对于您的用户如何?
要查看其外观示例,请参见{{link2:http://createguid.com/}}
此外,该GUID相当长;因此,如果您有数百万用户,则在DB中有很多字节...因此,它可能不应用作任何主/外键。
考虑使用适合用户数量的最小整数作为主键或外键,因为这个数值会在应用程序的许多地方重复出现;并且将“长用户ID”仅存储一次在用户表中。保留HTML标签。

密码是为用户存在的,是的...我想我可能深入了一点...基本上我只需要一种安全的方式来保护用户,但也只是为了在数据库逻辑中识别用户。我可以让人们看到用户的公共ID,因为他们的DB级别ID是隐藏和唯一的。他们也无法访问Web服务,并且需要经过身份验证才能访问任何可能危险的功能。 - brack
此外,该ID的意图是按照您所提到的方式进行存储 - 我希望仅在用户核心表中存储长用户ID,并通过其他用户表引用它。我正在使用增量int id,但我想将其隐藏并永远不将其暴露在PHP和MySQL之外。 - brack

1
我写了一个类,可以为您提供一个24个字符的唯一ID,与MongoDB的ID字段兼容(并使用相同的构造逻辑)。将来可能会有用。
<?php
/**
 * Generator for Mongo-like ObjectIds in pure PHP
 * Author: Mauricio Piacentini
 *
 * Inspired by https://github.com/justaprogrammer/ObjectId.js
 *
 */

class ObjectIdFactory
{   
    private $_datetime = null;
    private $_machine = null;
    private $_pid = null;
    private $_increment = null;

    public function __construct()
    {
        $this->_machine = str_pad(dechex(rand(0, 16777215)), 6, "0", STR_PAD_LEFT);
        $this->_pid = str_pad(dechex(rand(0, 32767)), 4, "0", STR_PAD_LEFT);
        $this->_increment = rand(0, 16777215);

        //We need a DateTime object to get timestamps, cache it
        $this->_datetime = new DateTime();
    }

    public function getNewId($forcedincrement = null)
    {
        if (is_null($forcedincrement)) {
            $this->_increment++;
            if ($this->_increment > 0xffffff) {
                $this->_increment = 0;
            }
        } else {
            $this->_increment = $forcedincrement;
        }
        $timestamp = $this->_datetime->getTimestamp();

        $timestamp_final = str_pad(dechex($timestamp), 8, "0", STR_PAD_LEFT);
        $increment_final = str_pad(dechex($this->_increment), 6, "0", STR_PAD_LEFT);
        return $timestamp_final . $this->_machine . $this->_pid . $increment_final;
    }

}

https://github.com/piacentini/ObjectId.php


0

个人而言,我使用md5(uniqid(mt_rand(),true))生成32个字符标识符(128位十六进制数),非常难以预测。


0

你有考虑过使用UUID吗?

快速的谷歌搜索可以得到一些好的资源/链接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接