mysql - 可重复生成有限制的个人 ID

标签 mysql hash

希望有人能帮助我。

我想生成一个个人 ID。由于 Moodle 的插件,我有以下限制:

  • ID不能超过9
  • ID 只能包含数字 [0-9]

ID 不应是随机数。如果可能的话,我希望能够使用此人的一些基本信息重新创建它。

我的方法:

目前我执行以下步骤来生成 ID。

1) 我获取主键、名字和姓氏并进行 MD5 哈希。

        USE `bpmspace_coms_v1`;

        DELIMITER //
        DROP PROCEDURE IF EXISTS demo_data;

        //

        CREATE PROCEDURE  demo_data()
        begin
        DECLARE x SMALLINT DEFAULT 0;
          while x < 100 
          do
            SET @lastname = generate_lname();
            SET @firstname = generate_fname();

            INSERT INTO .`coms_participant` (`coms_participant_lastname`, `coms_participant_firstname`, `coms_participant_public`, `coms_participant_placeofbirth`, `coms_participant_birthcountry`) VALUES (@lastname, @firstname, '0', str_random('Cccc(4)'), str_random('Cccc(7)'));
            SET @lastid = LAST_INSERT_ID();
            INSERT INTO `coms_participant_identifier` (`coms_participant_id`, `coms_participant_matriculation`, `coms_participant_md5`) VALUES (@lastid, @lastid, md5(concat(@lastid,@firstname,@lastname)));

            set x = x+1;

          end while;

        END;

        //

        DELIMITER ;
        call demo_data()

2) 然后我剪切前 7 个十六进制值 (fffffff = 268.435.455 ) 并将它们转换为数字

UPDATE `coms_participant_identifier` set `coms_participant_matriculation` = CONV(SUBSTRING(coms_participant_md5,1,7),16,10) where true;

有没有更好的方法?您预计什么时候会发生碰撞?

谢谢你的帮助,

罗布

下面是涉及到的2个表的创建语句

CREATE TABLE `coms_participant` (
  `coms_participant_id` int(11) NOT NULL AUTO_INCREMENT,
  `coms_participant_lastname` varchar(60) DEFAULT NULL,
  `coms_participant_firstname` varchar(60) DEFAULT NULL,
  `coms_participant_public` tinyint(4) DEFAULT '0',
  `coms_participant_placeofbirth` varchar(60) DEFAULT NULL,
  `coms_participant_birthcountry` varchar(60) DEFAULT NULL,
  `coms_participant_dateofbirth` date DEFAULT NULL,
  `coms_participant_LIAM_id` int(11) NOT NULL,
  PRIMARY KEY (`coms_participant_id`)
) ENGINE=InnoDB AUTO_INCREMENT=52807563 DEFAULT CHARSET=utf8;


CREATE TABLE `coms_participant_identifier` (
  `coms_participant_identifier_id` int(11) NOT NULL AUTO_INCREMENT,
  `coms_participant_id` int(11) NOT NULL,
  `coms_participant_matriculation` double NOT NULL,
  `coms_participant_md5` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`coms_participant_identifier_id`),
  UNIQUE KEY `coms_participant_identifier_id_UNIQUE` (`coms_participant_identifier_id`)
) ENGINE=InnoDB AUTO_INCREMENT=229583147 DEFAULT CHARSET=utf8;

我使用来自 https://thecodecave.com/tag/mysql/ 的 generate_lname() 和 generate_fname() 和来自 http://moinne.com/blog/ronald/mysql/howto-generate-meaningful-test-data-using-a-mysql-function 的 str_random()

最佳答案

1) I take the primary key, the firstname and the lastname and do an MD5 hash.

如果您不必使用 MD5,请不要使用。它完全坏了。 SHA-1 也在崩溃。使用 SHA-256。虽然由于下一部分而有点没有实际意义......

I want to generate a personal ID. I have - due to a Plugin of Moodle - the following limitations:

  • the ID must not be longer than 9
  • the ID must contain only digits [0-9]

这很糟糕。这意味着只有 10 亿个可能的 ID,这可能看起来很多,但它非常小,大约 30 位。使用这么小的 key 空间,您发生哈希冲突。您的实现仅使用其中的 28 个位,使其更小。别担心,这 2 位无关紧要。

当两个字符串具有相同的哈希时,就会发生哈希冲突。通常这不是问题,因为散列空间很大,但您的空间很小。例如,SHA-1 是 160 位或大 40 个数量级。 40 orders of magnitude is the difference between the size of a virus and the size of a planet.只有 10 亿种可能性,您很可能会发生碰撞,比您想象的可能性大得多。

您可能会想“如果我有 10 亿个 ID 并且我有 100 万用户,那么发生冲突的可能性只有 1/1000”,但事实并非如此。这被称为 the Birthday Problem它的漏洞被称为the Birthday Attack .长话短说,在大约 10,000 到 20,000 名用户处发生碰撞的几率为 50/50。

我使用 /usr/share/dict/words 运行了一个简短的模拟,并在 11371 个单词后发生了碰撞。

require "digest"

hashes = {}

count = 0
File.new("/usr/share/dict/words").each { |line|
    line.chomp!
    
    count += 1
    
    hash = Digest::MD5.hexdigest(line)[0..6]
    if hashes[hash]
        puts "#{line} collides with #{hashes[hash]} after #{count} words: #{hash}"
    end
    
    hashes[hash] = line
}

aplasia collides with antefurcal after 11371 words: 7417bf5
circumvolant collides with angelicalness after 36704 words: d8ae33c
debord collides with Actinopteri after 49183 words: c43674a
dichromasy collides with acetolytic after 53190 words: 102ef7d
diplosphene collides with aruke after 54247 words: cdce4ec
divaricate collides with chemurgic after 56200 words: b7d936c
draftily collides with backvelder after 57533 words: dcb75a2
firefall collides with Cytophaga after 70180 words: ae25f13
...

这意味着您需要某种方式 resolving that collision .这意味着无法预测给定用户获得的哈希值,因为哈希值的顺序很重要。

对于如此小的 key 空间,某人通过蛮力生成有效 key 将相对简单。


鉴于如此小的键空间,我会问一些基本问题。

  • 这真的是一个限制吗?
    • 如果是这样,我真的需要这个插件吗?
  • 为什么我需要能够重新创建他们的散列?
    • 可以为它们分配一个像 UUID 这样的哈希值吗?

关于mysql - 可重复生成有限制的个人 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43198499/

相关文章:

php - 尝试在表单提交中插入 NULL 日期但得到 00 :00

php - 避免在全文列中重复输入

algorithm - 有了哈希和密码,我可以重新创建算法吗?

data-structures - 在哈希表中重新哈希

perl - Perl 是否保证返回一致有序的散列键?

algorithm - 使用链接散列并使用大小为 `m` 的表

php - 如何再次从1开始更新id列

javascript - 从 Javascript 中的回调函数获取变量

c# - 在 C# 中解码 mysqlbinlog

PHP 优化这是正确的吗?