使用SecureRandom.hex时有什么机会获得副本?

时间:2018-11-07 09:46:04

标签: ruby-on-rails ruby algorithm combinations probability

我计划使用SecureRandom.hex为我的用户生成API密钥。

到目前为止,这里是3次执行的输出:

Loading development environment (Rails 5.2.1)
2.3.5 :001 > SecureRandom.hex
 => "0369e9b7c6ffa07bd8d0a263f7b4cfa6" 
2.3.5 :002 > SecureRandom.hex
 => "1a8a168d7f70676451e3d59353e22693" 
2.3.5 :003 > SecureRandom.hex
 => "94cc188e9e5c3abfe587510fa79993ce"

我得到重复结果的机会是什么?

我创建的这种方法会真正避免产生重复的内容吗?

def generate_string
  string = SecureRandom.hex

  generate_string if Model.where(:key => string).count > 0

  string
end

unique_string = generate_string

我正在使用递归,如果该字符串已经存储在数据库中,它将只产生另一个。

而且,由于我没有得到重复,因此SecureRandom.hex可以用多少个字符串才能用尽组合来产生?

3 个答案:

答案 0 :(得分:1)

由于它是一个以16为基数的数字系统,因此存在16 ** SecureRandom.hex.length可能的变化,而且很多。

如果您不想在用户数量增加时使堆栈溢出,则最好在退出条件下使用循环。

MAX_ATTEMPTS = 3 # For you to choose.

def key
  MAX_ATTEMPTS.times do
    hex = SecureRandom.hex
    return hex unless Model.where(key: hex).exists?
  end

  fail 'No attempts to generate a key left.'
end

答案 1 :(得分:1)

在您的示例中(使用默认长度为32的SecureRandom.hex时)

16**32 = 340282366920938463463374607431768211456

可能有不同的十六进制值。这意味着1:340282366920938463463374607431768211456有机会创建一个副本。这次机会极低,恕我直言,不必为此担心太多。

当您要将密钥存储在数据库中时,我建议向该数据库列添加唯一索引,以确保在数据库级别上不可能存储任何重复项。

此外,您询问示例代码是否足以避免重复。答案是。这是高度理论上的,因为可能性很低,但是您可能会遇到竞争情况,在这种情况下,两个作业同时生成相同的密钥,同时检查数据库中是否没有这样的密钥以及两个作业存储的密钥是​​否相同值插入表格。

重复的机会极低。数据库中key列上的唯一索引可确保不会有任何重复(因为竞争条件或绕过此方法生成的键)。

答案 2 :(得分:1)

在您的设置中,键的长度似乎是32。

  • 在三个执行中没有重复的机会是:

    ((16**32 - 1)/16**32) * ((16**32 - 2)/16**32)
    

    因此,在三个执行中某处获得(至少一对)重复的机会是:

    1 - ((16**32 - 1)/16**32) * ((16**32 - 2)/16**32)
    = 8.8162076e-39
    
  • 有:

    16**32 = 3.4028237e+38
    

    不同的字符串。

  • 您的方法可以按预期工作时避免重复,但它也具有不可思议的微小可能性,使其永久消失并且永不终止。