【发布时间】:2017-06-17 15:35:59
【问题描述】:
我在 StackOverflow 上看到了一堆 different solutions,它们跨越了很多年和许多 Postgres 版本,但是有一些较新的功能,例如 gen_random_bytes 我想再次询问是否有更新的更简单的解决方案版本。
给定的 ID 包含 a-zA-Z0-9,并且大小会根据它们的使用位置而有所不同,例如...
bTFTxFDPPq
tcgHAdW3BD
IIo11r9J0D
FUW5I8iCiS
uXolWvg49Co5EfCo
LOscuAZu37yV84Sa
YyrbwLTRDb01TmyE
HoQk3a6atGWRMCSA
HwHSZgGRStDMwnNXHk3FmLDEbWAHE1Q9
qgpDcrNSMg87ngwcXTaZ9iImoUmXhSAv
RVZjqdKvtoafLi1O5HlvlpJoKzGeKJYS
3Rls4DjWxJaLfIJyXIEpcjWuh51aHHtK
在 Postgres 9.6+ 中,如何通过一种简单的方法为不同的用例指定不同的长度,从而随机且安全地生成它们(就减少冲突和降低可预测性而言)?
我认为理想情况下该解决方案的签名类似于:
generate_uid(size integer) returns text
size 可根据您自己的权衡来定制,以降低冲突的机会与减小字符串大小以提高可用性。
据我所知,它必须使用gen_random_bytes() 而不是random() 来实现真正的随机性,以减少被猜到的机会。
谢谢!
我知道 UUID 有 gen_random_uuid(),但我不想在这种情况下使用它们。我正在寻找能够为我提供类似于 Stripe(或其他)使用的 ID 的东西,看起来像:"id": "ch_19iRv22eZvKYlo2CAxkjuHxZ",它尽可能短,同时仍然只包含字母数字字符。
这个要求也是为什么encode(gen_random_bytes(), 'hex') 不太适合这种情况,因为它减少了字符集,从而迫使我增加字符串的长度以避免冲突。
我目前正在应用程序层执行此操作,但我希望将其移至数据库层以减少相互依赖性。以下是在应用层执行此操作的 Node.js 代码可能如下所示:
var crypto = require('crypto');
var set = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
function generate(length) {
var bytes = crypto.randomBytes(length);
var chars = [];
for (var i = 0; i < bytes.length; i++) {
chars.push(set[bytes[i] % set.length]);
}
return chars.join('');
}
【问题讨论】:
-
N的范围是多少? -
@IanStorm。我回答了这个问题,因为我看到了很多。但是,实际上我认为它不应该在这里使用“唯一标识符”一词。如果你想要胡言乱语,你可以拥有它,无论如何。但是标识符而不是 UUID 非常愚蠢,恕我直言。这就是它的用途。
-
感谢@EvanCarroll!我使用术语“标识符”是因为那是我的用例,但更重要的是因为我认为它意味着必要的安全性——结果不应该是可预测的,类似于使用
SERIAL在这种情况下不起作用。我知道 UUID 是为此而设计的,但我希望对输出长度和“外观”有更多的控制,就所使用的字符而言——类似于 Youtube 或其他人为短 URL 代码所做的事情。 -
@kevlarr 如果
62**10的熵永远不够。这就是伊恩正在做的事情。他将 10 个字节存储在 14 个字节的存储空间中,用于62**10位熵。当他可以在 16 个字节中拥有2**128 bits时(碰撞的可能性大大降低,作为标准,这是你这样做的方式),或者他可以使用具有 0 碰撞机会并返回较小密钥的盐渍哈希猫
标签: sql database postgresql random