3

如果我有 10,000 个用户并且主键是从 1 到 10,000 的唯一 ID,有没有办法给他们所有人一个唯一 ID,这样就无法从中推断出原始主键?

例如,链接到您的 facebook 个人资料或类似内容将是http://site.com/profile?id=293852

那里的 id 是否可能与其用户在数据库中的主键相同?我正在努力想办法让两个不相关的唯一 ID 列,因为随机生成的必须是唯一的。我想如果有可能只有使用数字的 GUID 长度会太长。

和想法?

4

5 回答 5

2

出于安全原因,确实建议使 ID 不连续,以避免在系统中枚举用户。但是 40 亿(我的意思是 2^32)太小,无法提供不可发现的间隔。这就是为什么 GUID 更可取的原因。根据数据库(查看您的规范,它看起来像 MSSQL),您可以存储在类似 guid 的字段、字节字段(对于 MySQL)或 2 个单独的 int64 中。

为了减小 URL 大小,可以应用 base64 编码,这样 GUID 看起来更短。

于 2011-02-14T10:55:38.860 回答
2

您通常有两种选择:

  1. 正如你所说,使用随机生成的数据。(您只需要确保它们是唯一的,即足够长,或者生成-验证-重试。)
  2. 获取主键并将其“伪随机”转换为其他似乎与主键无关的东西。转换可能非常简单(如果您只想要一个温和的保护),例如new Random(primaryKey).NextInt(),或者它可能非常复杂,但可以防止攻击,例如任何类型的保留格式的加密

但是……为什么你认为你应该保护你的主键的值?如果唯一的原因是为了防止用户猜测其他有效的用户 ID,您可以将一个随机字符串附加到主键(并将其存储在数据库中并在访问时验证其正确性)。

于 2011-02-14T10:56:52.843 回答
1

如何生成随机且唯一的 id 是一个有用的问题 - 但您似乎在假设何时生成它们!

我的观点是,您不需要在创建行时生成这些 id,因为它们本质上独立于插入的数据。

我所做的是预先生成随机 id 以供将来使用,这样我就可以度过自己的美好时光并绝对保证它们是独一无二的,并且在插入时无需进行任何处理。

例如,我有一个带有 order_id 的订单表。此 ID 在用户输入订单时即时生成,以 1、2、3 等方式永远递增。用户不需要看到这个内部 id。

Then I have another table - random_ids with (order_id, random_id). I have a routine that runs every night which pre-loads this table with enough rows to more than cover the orders that might be inserted in the next 24 hours. (If I ever get 10000 orders in one day I'll have a problem - but that would be a good problem to have!)

This approach guarantees uniqueness and takes any processing load away from the insert transaction and into the batch routine, where it does not affect the user.

于 2011-08-05T11:02:30.103 回答
0

允许用户查看主键有什么问题?

您可以随机生成数字,确保它是一个非常大的数字,以便不太可能发生冲突,然后只需运行选择以检查它不存在。

或者,您可以选择一个巨大的数字,然后围绕它建立一些方程式。就像是:

unique = 1000000000 * (-1 * PK)^3

这意味着随着 PK 的增加,唯一编号将远离您的起始编号,并根据 PK 是奇数还是偶数而高于或低于它。您添加到等式中的复杂性越多,它被发现的可能性就越小,但永远不会 100% 依赖这种方法,因为总有可能有人会解决它。

于 2011-02-14T10:55:57.220 回答
0

我所做的是使用部分 GUID 和实际 ID。

在表中,我有一个列类型 uniqueidentifier,默认值为 newid()

然后我参与其中并在末尾添加实际的序列号,并在它们之间添加一个已知的分隔符。我使用字母 H,因为它不会出现在 GUID 中。

所以对于第 8659 行,我将有:
IDcolumn=8659
GUIDcolumn='{200BAB55-C7D5-4456-AB57-CFF8B7E82A90}'
PROFILECODE='200BAB55H8659'

我可以通过以下方式找到正确的行:

partGUID=split(PROFILECODE,'H')(0) - gives 200BAB55
realID=split(PROFILECODE,'H')(1) - give 8659
select * from mytable where IDcolumn=8659 and left(GUIDcolumn,8)='200BAB55';

理论上,SQL 解析器应该首先找到 IDcolumn 8659 的所有行,然后检查 GUIDcolumn

如果人们试图猜测配置文件的 ID,他们不能只更改其中的一部分并成功。

于 2011-02-14T10:59:04.717 回答