Ruby 使用rand生成uuid是否不安全?
要创建非连续、唯一的用户id,我知道我可以使用:Ruby 使用rand生成uuid是否不安全?,ruby,Ruby,要创建非连续、唯一的用户id,我知道我可以使用: SecureRandom.uuid 问题是它有点慢,我们被API的响应能力所困扰。我正在尝试确定是否可以用以下内容替换id生成: rand(36**10).to_s(36) 这是更快的,并生成一个看似随机的,通常是10位字母数字。这安全吗?rand真的会在36^10~3.5e15巨大的可能性空间中生成或多或少均匀分布的id吗?或者在实践中,分布是否会不均匀,从而更有可能产生碰撞 P>我应该知道的或者其他的选择我应该考虑? < P>也许你可以
SecureRandom.uuid
问题是它有点慢,我们被API的响应能力所困扰。我正在尝试确定是否可以用以下内容替换id生成:
rand(36**10).to_s(36)
这是更快的,并生成一个看似随机的,通常是10位字母数字。这安全吗?rand
真的会在36^10~3.5e15
巨大的可能性空间中生成或多或少均匀分布的id吗?或者在实践中,分布是否会不均匀,从而更有可能产生碰撞
<> P>我应该知道的或者其他的选择我应该考虑? < P>也许你可以把这个缓慢的过程移到背景:
- 在快速数据存储(例如Redis)中保留UUID池
- 当API需要uuid时,获取最旧的uuid并将其从池中删除
- 有一个后台作业,用于监视池,并在大小降至限制以下时添加新的uuid
随机方法的安全性,但无论如何:
您提到,您需要随机数来生成碰撞概率较低的用户ID。我认为不值得讨论性能问题:
require 'benchmark'
require 'securerandom'
n = 100_000
Benchmark.bmbm(15) do |x|
x.report("random:") { n.times do; rand(36**10).to_s(36); end }
x.report("uuid:") { n.times do; SecureRandom.uuid; end }
x.report("hex:") { n.times do; SecureRandom.hex; end }
end
# Rehearsal ---------------------------------------------------
# random: 0.070000 0.010000 0.080000 ( 0.062774)
# uuid: 0.800000 0.000000 0.800000 ( 0.802512)
# hex: 0.360000 0.000000 0.360000 ( 0.361002)
# ------------------------------------------ total: 1.240000sec
#
# user system total real
# random: 0.060000 0.000000 0.060000 ( 0.062458)
# uuid: 0.820000 0.000000 0.820000 ( 0.820784)
# hex: 0.340000 0.000000 0.340000 ( 0.341963)
你说得对。SecureRandom.uuid
比random
慢13倍。但您仍然能够每毫秒生成约1000个UUID。这对于在数据库中存储这样一个uuid所需的时间来说是微不足道的。IMO数据库更新至少需要2-3毫秒
此外,SecureRandom.uuid
的可读性比您的rand(36**10)要好得多。谢谢。这是个好主意,它会解决我的问题。然而,如果rand
代码实际上是相当安全的,我更喜欢这种解决方案,因为它更简单。没错,它更复杂,但我认为它远没有证明随机数生成器是安全的那么难。是的,但请记住,我没有用它来加密信用卡或类似的东西。我只需要创建唯一的用户ID,其冲突概率非常低,并且相当难以猜测。认为调用Redis这样的外部服务比简单的SecureRandom.uuid
更快是荒谬的Benchmark.measure{100000.times{SecureRandom.uuid}}。总计
在我的旧MacBook上返回0.78秒以下。这意味着每毫秒约1000个uuid。我从未使用过SecureRandom,所以我不知道它有多快。OP似乎认为它很慢。我并不是说它会更快,只是展示了一种使API更具响应性的技术。还有一个工具箱工具。哇,奇怪,当我在IRB中运行它时,会有一秒钟的停顿来生成一个one@Jonah这很奇怪;您可能需要提供其他详细信息。我无法在任何系统上重现这种行为。好的,所以在第一次呼叫时,它似乎只有1-2秒的延迟。我启动irb,然后执行要求的'securerandom'
,然后执行securerandom.uuid
--暂停1-2秒,然后执行结果。然后,如果我再调用SecureRandom.uuid
,它会立即返回。@Jonah也无法重现,但还行。您是否确实确定(a)您有性能瓶颈,以及(b)您的数据库还不能生成uuid?(a)请参阅我对@spickermann的回复。(b) 我不知道答案是什么,我现在正在使用redis,但计划在生产中切换到postgres,或者其他东西。(a)请参阅我对您答复的答复,(b)postgres有UUID;我个人认为不使用SecureRandom的UUID没有多大价值。