1

在内部,我的网站将用户存储在由整数主键索引的数据库中。

但是,我想将用户与许多独特的、难以猜测的标识符相关联,每个标识符将在各种情况下使用。例子:

  • 一个用于用户配置文件 URL:因此可以通过不包含其实际主键的 URL 找到和显示用户,从而防止配置文件被抓取。
  • 一个用于无登录电子邮件退订表单:因此用户可以通过单击电子邮件中的链接来更改他们的电子邮件首选项,而无需登录,从而防止其他人能够轻松猜测 URL 并篡改他们的电子邮件首选项。

正如我所看到的,我需要这些标识符的关键特征是它们不容易被猜到,它们是唯一的,并且知道密钥或标识符不会很容易找到另一个。

有鉴于此,我正在考虑在创建新用户时使用SecureRandom::urlsafe_base64生成多个随机标识符,一个用于每个目的。由于它们是随机的,因此我需要在插入之前进行数据库检查以保证唯一性。

任何人都可以提供健全性检查并确认这是一种合理的方法吗?

4

2 回答 2

3

您使用的方法是使用安全的随机生成器,因此即使知道其中一个 URL,也很难猜测下一个 URL。在生成随机序列时,要记住一个关键方面:不安全的随机生成器可以变得可预测,并且具有一个值可以帮助预测下一个值是什么。你可能对这个没问题。

此外,urlsafe_base64在其文档中说默认随机长度为 16 个字节。这为您提供了 8 16 个不同的可能值 (2.81474977 × 10 14 )。这不是一个巨大的数字。例如,这意味着每秒执行 10.000 次请求的爬虫将能够在大约 900 年内尝试所有可能的标识符。现在似乎可以接受,但是计算机变得越来越快,并且根据您的应用程序的规模,这可能是未来的问题。只是使第一个参数更大可以解决这个问题。

最后,您绝对应该考虑的事情:您的数据库被泄露的可能性。即使您的标识符是防弹的,您的数据库也可能不是,攻击者可能能够获得所有标识符的列表。您绝对应该使用安全散列算法(使用适当的盐,与密码相同)对数据库中的标识符进行散列。只是为了让您了解这有多重要,使用最近的 GPU,SHA-1 可以以每秒 350.000.000 次尝试的速度被强制执行。使用 SHA-1 散列的 16 字节密钥(您使用的方法的默认值)将在大约 9 天内被猜到。

总结:算法已经足够好了,但是增加了keys的长度,并在数据库中hash。

于 2012-07-04T16:00:09.093 回答
2

因为生成的 id 不会与任何其他数据相关,所以它们将很难(不可能)猜到。为了快速验证唯一性并找到用户,您必须在数据库中对它们进行索引。

您还需要编写一个返回唯一 id 检查唯一性的函数,例如:

def generate_id(field_name)
  found = false
  while not found
    rnd = SecureRandom.urlsafe_base64
    found = User.exists?(field_name: rnd)
  end
  rnd
end

最后一次安全检查,在进行任何更改之前尝试检查标识符和用户信息之间的对应关系,至少是电子邮件。

也就是说,这对我来说似乎是一个很好的方法。

于 2012-07-04T15:56:19.423 回答