如何在不使用数据库中的主键的情况下为用户提供唯一ID?

时间:2011-02-14 10:46:26

标签: asp.net sql unique-index

如果我有10,000个用户且主键是从1到10,000的唯一ID,是否有办法为它们提供所有唯一ID,以便无法从中推断出原始主键?

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

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

和想法?

5 个答案:

答案 0 :(得分:2)

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

要减小URL大小,可以应用base64编码,以便GUID看起来更短。

答案 1 :(得分:2)

您通常有两种选择:

  1. 正如您所说,使用随机生成的数据。 (您只需要确保它们是唯一的,即要么足够长,要么生成验证重试。)
  2. 获取主键并将其“伪随机”转换为似乎与主键无关的其他内容。转换可能非常简单(如果你只需要一个温和的保护),例如new Random(primaryKey).NextInt(),或者它可能非常复杂,但可以防攻击,例如任何类型的Format-preserving encryption
  3. 但是......为什么你认为你应该保护主键的价值?如果唯一的原因是阻止用户猜测其他有效的用户ID,您只需将随机字符串附加到主键(并将其存储在数据库中并验证其访问的正确性)。

答案 2 :(得分:1)

如何生成随机和唯一ID是一个有用的问题 - 但您似乎在 生成它们时做出了假设!

我的观点是,您在创建行时不需要生成这些ID,因为它们基本上与所插入的数据无关。

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

例如,我有一个带有order_id的订单表。当用户输入订单时,会立即生成此ID,永久递增1,2,3等。用户无需查看此内部ID。

然后我有另一个表 - random_ids(order_id,random_id)。我有一个每天晚上运行的例程,它预先加载了足够多的行,以覆盖可能在接下来的24小时内插入的订单。 (如果我在一天内获得10000份订单,​​我就会遇到问题 - 但这将是一个很好的问题!)

这种方法保证了唯一性,并且可以将任何处理负载从插入事务转移到批处理例程中,而不会影响用户。

答案 3 :(得分:0)

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

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

或者,你可以选择一个庞大的数字,然后围绕它做一些方程式。类似的东西:

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

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

答案 4 :(得分:0)

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

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

然后我参与其中并在末尾添加实际的序列ID,并在它们之间使用已知的分隔符。我使用字母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的所有行,然后检查GUID列

如果人们试图猜测个人资料的ID,他们就不能只改变其中的一部分并取得成功。