使用rand生成uuid是不安全的吗?

时间:2014-05-09 23:56:01

标签: ruby

为了创建非连续的唯一用户ID,我知道我可以使用:

SecureRandom.uuid

问题在于它有点慢,我们对API的响应能力很着迷。我试图确定我是否可以用这样的东西替换id代:

rand(36**10).to_s(36)

更快,并生成一个看似随机的,通常为10位的字母数字。这样安全吗? rand 36^10 ~ 3.5e15会在{{1}}大的可能性范围内真正生成或多或少均匀分布的ID吗?或者在实践中,分布是不均匀的,因此更容易产生碰撞?

我应该考虑的任何其他问题或我应该考虑的替代方案?

2 个答案:

答案 0 :(得分:2)

这是一个有点偏离主题,因为你询问了random方法的安全性,但无论如何:

您提到需要随机数来生成碰撞概率较低的user_ids。我认为讨论性能问题是不值得的:

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.uuidrandom慢13倍。但是你仍然可以每毫秒生成~1000 uuids。这在数据库中存储这样的uuid所需的时间可以忽略不计。 IMO对数据库的更新至少需要2-3ms。

此外,SecureRandom.uuid的可读性远远优于rand(36**10).to_s(36)

答案 1 :(得分:1)

也许你可以将缓慢的过程移到后台:

  • 在快速数据存储区(例如Redis)中保留一组uuids。
  • 当API需要uuid时,请获取最旧的uuid并将其从池中删除。
  • 有一个监视池的后台作业,并在大小低于限制时添加新的uuid。