Web 应用程序中随机 id 的方法是什么

发布于 2024-10-28 02:04:05 字数 811 浏览 5 评论 0原文

我的 URL 看起来像这样:

http://domain.com/object/23/

我希望 23 不是连续的并且相当随机。我在 Stack Overflow 上看到过许多其他帖子询问同样的事情,但我的要求与我所看到的有点不同。

我的许多使用该网站的人都是竞争对手,他们很容易通过一些数字来获取竞争信息。我这样做不是为了安全,而且我知道通过默默无闻来实现安全是浪费时间。我只是在寻找一种快速的方法来防止人们四处闲逛。

我正在使用 python/SQLAlchemy 和 Postgres 数据库来完成此操作。我查看了 UUID 主键,但它们似乎对性能造成了很大的影响,因为我发生了很多连接。我还可以在附加列中执行 UUID,然后根据顺序积分主键执行所有连接。

大多数需要此功能的表的记录数都少于 1000 条。但一张表会有几百万条记录。如果没有那个表,我只会使用 uuid 并完成它。但既然我这样做了,我真的不认为 uuid 是一个很好的选择。

真正的问题是我还有什么其他选择。

  1. 使用顺序数字主键,但在数据库外部时使用某种轻量级算法动态加密/解密它们

  2. 单独的列,并在创建行时生成的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.

  1. Use sequential numeric primary key, but encrypt/decrpyt them on the fly when outside of the database with some light weight algorithm

  2. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

傲影 2024-11-04 02:04:05

为了从序列中生成唯一且看起来随机的标识符,使用密码可能是一个好主意。由于它们的输出是双射的(输入和输出值之间存在一对一的映射)——与哈希不同,您将不会发生任何冲突。这意味着您的标识符不必像哈希值一样长。

大多数加密密码都在 64 位或更大的块上工作,但 PostgreSQL wiki 有一个用于适用于(32 位)int 类型的“非加密”密码 函数。免责声明:我自己没有尝试过使用此功能。

要将其用作主键,请从 wiki 页面运行 CREATE FUNCTION 调用,然后在您的表上执行以下操作:

ALTER TABLE foo ALTER COLUMN foo_id SET DEFAULT pseudo_encrypt(nextval('foo_foo_id_seq')::int);

瞧!

pg=> insert into foo (foo_id) values(default);
pg=> insert into foo (foo_id) values(default);
pg=> insert into foo (foo_id) values(default);
pg=> select * from foo;
  foo_id   
------------
 1241588087
 1500453386
 1755259484
(4 rows)

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:

ALTER TABLE foo ALTER COLUMN foo_id SET DEFAULT pseudo_encrypt(nextval('foo_foo_id_seq')::int);

And voila!

pg=> insert into foo (foo_id) values(default);
pg=> insert into foo (foo_id) values(default);
pg=> insert into foo (foo_id) values(default);
pg=> select * from foo;
  foo_id   
------------
 1241588087
 1500453386
 1755259484
(4 rows)
爱殇璃 2024-11-04 02:04:05

对于您想要实现的目标来说,散列/加密似乎有点矫枉过正。一个单独的列存储 10000 到 99999(或 100000、999999 等)之间的随机数,然后像这样链接:

http://domain.com/object/23-74938/

其中“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:

http://domain.com/object/23-74938/

where the '74938' is the random bit

桜花祭 2024-11-04 02:04:05

我会选择类似选项 2 的方法:例如,使用 HMAC 和 SHA1 来生成一个哈希值,该值可以针对每个请求进行验证,甚至无需靠近数据库。我经常制作这样的防篡改“票”。例如

use Digest::HMAC_SHA1 qw(hmac_sha1_hex);
$id = shift;
print "$id.", substr(hmac_sha1_hex($id, "s3kr1t"), 0, 8), "\n"

,要验证:

use Digest::HMAC_SHA1 qw(hmac_sha1_hex);
$tkt = shift;
($id,$sum) = ($tkt =~ /(.+)\.([0-9a-f]+)/)
        or die "Invalid tkt (bad format): $tkt\n";
$sum eq substr(hmac_sha1_hex($id, "s3kr1t"), 0, 8)
        or die "Invalid tkt (MAC mismatch): $tkt\n";
print $id, "\n"

这会生成 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.

use Digest::HMAC_SHA1 qw(hmac_sha1_hex);
$id = shift;
print "$id.", substr(hmac_sha1_hex($id, "s3kr1t"), 0, 8), "\n"

And to verify:

use Digest::HMAC_SHA1 qw(hmac_sha1_hex);
$tkt = shift;
($id,$sum) = ($tkt =~ /(.+)\.([0-9a-f]+)/)
        or die "Invalid tkt (bad format): $tkt\n";
$sum eq substr(hmac_sha1_hex($id, "s3kr1t"), 0, 8)
        or die "Invalid tkt (MAC mismatch): $tkt\n";
print $id, "\n"

This produces a "ticket" of "23.3b30e326" for id 23.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文