Web 应用程序中随机 id 的方法是什么
我的 URL 看起来像这样:
http://domain.com/object/23/
我希望 23 不是连续的并且相当随机。我在 Stack Overflow 上看到过许多其他帖子询问同样的事情,但我的要求与我所看到的有点不同。
我的许多使用该网站的人都是竞争对手,他们很容易通过一些数字来获取竞争信息。我这样做不是为了安全,而且我知道通过默默无闻来实现安全是浪费时间。我只是在寻找一种快速的方法来防止人们四处闲逛。
我正在使用 python/SQLAlchemy 和 Postgres 数据库来完成此操作。我查看了 UUID 主键,但它们似乎对性能造成了很大的影响,因为我发生了很多连接。我还可以在附加列中执行 UUID,然后根据顺序积分主键执行所有连接。
大多数需要此功能的表的记录数都少于 1000 条。但一张表会有几百万条记录。如果没有那个表,我只会使用 uuid 并完成它。但既然我这样做了,我真的不认为 uuid 是一个很好的选择。
真正的问题是我还有什么其他选择。
使用顺序数字主键,但在数据库外部时使用某种轻量级算法动态加密/解密它们
单独的列,并在创建行时生成的primary_key + Secret_key上使用sha1哈希(或其他哈希)。然后,我可以通过此哈希找到该行,并在正常 pk 上执行所有联接。
性能是这里最重要的事情,同时仍然保持一定程度的随机性和较低的碰撞几率。 #1 的加密/解密的最佳选项是什么,或者 #2 的最佳哈希算法是什么。还有比这两种方法更明显的方法吗?有了几百万行,uuid 不会让我的速度减慢太多,这就是解决方案吗?
I have URLs that look like this:
http://domain.com/object/23/
I would prefer the 23 to not be sequential and fairly random. I've seen may other posts on Stack Overflow asking the same thing but my requirements are a bit different than what I have seen.
Many of my the people using the site are competitors and it would be easy for them to poke around with some numbers to get competitive information. I'm not doing this for security and I understand that security through obscurity is a waste of time. I'm just looking for a quick way to keep people from poking around.
I'm doing this with python/SQLAlchemy with a Postgres database. I've looked at UUIDs primary key's but they seem like a large performance hit as I have alot of joins happening. I could also do UUID's in an additional column then do all joins based off of the sequential integral primary key.
Most tables that need this would have less than 1000 records. But 1 table would have a few million records. Without that table I would just use uuid and be done with it. But since I do I don't really think uuid is a great choice.
The real question is what are my other options then.
Use sequential numeric primary key, but encrypt/decrpyt them on the fly when outside of the database with some light weight algorithm
Separate column and use a sha1 hash (or other hash) on the primary_key + secret_key that is generated on the rows creation. I could then just find the row via this hash and the do all the joins on the normal pk.
Performance is the most important thing here, while still maintaining some level of randomness with low chance of collision. What are the best options for the encryption/decryption for #1 or what is the best hash algo for #2. Is there a way more obvious than either of these 2? With a few million rows is uuid not going to slow me down too much and thats the solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
为了从序列中生成唯一且看起来随机的标识符,使用密码可能是一个好主意。由于它们的输出是双射的(输入和输出值之间存在一对一的映射)——与哈希不同,您将不会发生任何冲突。这意味着您的标识符不必像哈希值一样长。
大多数加密密码都在 64 位或更大的块上工作,但 PostgreSQL wiki 有一个用于适用于(32 位)
int
类型的“非加密”密码 函数。免责声明:我自己没有尝试过使用此功能。要将其用作主键,请从 wiki 页面运行 CREATE FUNCTION 调用,然后在您的空表上执行以下操作:
瞧!
For generating unique and random-looking identifiers from a serial, using ciphers might be a good idea. Since their output is bijective (there is a one-to-one mapping between input and output values) -- you will not have any collisions, unlike hashes. Which means your identifiers don't have to be as long as hashes.
Most cryptographic ciphers work on 64-bit or larger blocks, but the PostgreSQL wiki has an example PL/pgSQL procedure for a "non-cryptographic" cipher function that works on (32-bit)
int
type. Disclaimer: I have not tried using this function myself.To use it for your primary keys, run the CREATE FUNCTION call from the wiki page, and then on your empty tables do:
And voila!
对于您想要实现的目标来说,散列/加密似乎有点矫枉过正。一个单独的列存储 10000 到 99999(或 100000、999999 等)之间的随机数,然后像这样链接:
其中“74938”是随机位
Hashing/encryption seem like overkill for what you are trying to achieve. How about a separate column storing a random number between 10000 and 99999 (or 100000, 999999 etc) then links like this:
where the '74938' is the random bit
我会选择类似选项 2 的方法:例如,使用 HMAC 和 SHA1 来生成一个哈希值,该值可以针对每个请求进行验证,甚至无需靠近数据库。我经常制作这样的防篡改“票”。例如
,要验证:
这会生成 id 23 的“23.3b30e326”“票据”。
I'd go with something like your option 2: use HMAC with SHA1 for example, to produce a hash value that can be verified for each request without even going near the database. I produce tamper-proof "tickets" like this quite often. e.g.
And to verify:
This produces a "ticket" of "23.3b30e326" for id 23.