如果我有 10,000 个用户并且主键是从 1 到 10,000 的唯一 ID,有没有办法给他们所有人一个唯一 ID,这样就无法从中推断出原始主键?
例如,链接到您的 facebook 个人资料或类似内容将是http://site.com/profile?id=293852
那里的 id 是否可能与其用户在数据库中的主键相同?我正在努力想办法让两个不相关的唯一 ID 列,因为随机生成的必须是唯一的。我想如果有可能只有使用数字的 GUID 长度会太长。
和想法?
如果我有 10,000 个用户并且主键是从 1 到 10,000 的唯一 ID,有没有办法给他们所有人一个唯一 ID,这样就无法从中推断出原始主键?
例如,链接到您的 facebook 个人资料或类似内容将是http://site.com/profile?id=293852
那里的 id 是否可能与其用户在数据库中的主键相同?我正在努力想办法让两个不相关的唯一 ID 列,因为随机生成的必须是唯一的。我想如果有可能只有使用数字的 GUID 长度会太长。
和想法?
出于安全原因,确实建议使 ID 不连续,以避免在系统中枚举用户。但是 40 亿(我的意思是 2^32)太小,无法提供不可发现的间隔。这就是为什么 GUID 更可取的原因。根据数据库(查看您的规范,它看起来像 MSSQL),您可以存储在类似 guid 的字段、字节字段(对于 MySQL)或 2 个单独的 int64 中。
为了减小 URL 大小,可以应用 base64 编码,这样 GUID 看起来更短。
您通常有两种选择:
new Random(primaryKey).NextInt()
,或者它可能非常复杂,但可以防止攻击,例如任何类型的保留格式的加密。但是……为什么你认为你应该保护你的主键的值?如果唯一的原因是为了防止用户猜测其他有效的用户 ID,您可以将一个随机字符串附加到主键(并将其存储在数据库中并在访问时验证其正确性)。
如何生成随机且唯一的 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.
允许用户查看主键有什么问题?
您可以随机生成数字,确保它是一个非常大的数字,以便不太可能发生冲突,然后只需运行选择以检查它不存在。
或者,您可以选择一个巨大的数字,然后围绕它建立一些方程式。就像是:
unique = 1000000000 * (-1 * PK)^3
这意味着随着 PK 的增加,唯一编号将远离您的起始编号,并根据 PK 是奇数还是偶数而高于或低于它。您添加到等式中的复杂性越多,它被发现的可能性就越小,但永远不会 100% 依赖这种方法,因为总有可能有人会解决它。
我所做的是使用部分 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,他们不能只更改其中的一部分并成功。