我有一个字段用户 ID,其值介于 10000 和 999999 之间。我想创建一个基于此字段的促销代码。
用户将使用促销代码来推荐新用户。
促销码特点:
- 数据库中没有附加字段 - 通过算法可以将促销代码解码回用户 ID
- 很难猜出用户名
- 易于口头分享
你能提出一些想法或例子来解决这个问题吗?
我有一个字段用户 ID,其值介于 10000 和 999999 之间。我想创建一个基于此字段的促销代码。
用户将使用促销代码来推荐新用户。
促销码特点:
你能提出一些想法或例子来解决这个问题吗?
数据库中没有附加字段 - 通过算法可以将促销代码解码回用户 ID
虽然这通常可以通过带有交叉引用的附加表来解决,理想情况下是 1:n,以便一个用户 ID 可以有多个有效的促销代码,但这似乎明显超出了范围。不幸的是,这也排除了自行选择的促销代码。
很难猜出用户名
理想情况下,根本不可能猜到用户 ID(并确保您猜对了)。
易于口头分享
这可能是不使用附加表的最大问题。
我提出以下解决方案:
加密您的用户 ID。
有不同的加密方案可能会产生较小的可用结果。但是,如果正如您对数据库更改的限制所建议的那样,实施成本是一个驱动因素,那么原始 rsa 可能值得一看,因为它使密文保持相对较小并且加密库很容易获得。
生成的位可以翻译成自然语言单词,例如使用diceware 的单词表。
使用这种方法,密文将易于通信(因为它是一串单词)并且易于破译(反向翻译,解密结果位)。
但是有一个问题:这些代码可能比预期的要长(取决于选择的加密方案),并且在输入它们时可能会造成时间损失。
虽然这会产生更长的(就字符串大小而言)代码,但它们比 base32、base64 或任何通常的传输编码方法更容易口头传输,尤其是对于母语人士而言。
因此,即使 1:n 表是理想的,但使用合适的加密方案并最终得到一个 3 字代码可能是下一个最好的事情 - 并且绝对比通常的编码数据嫌疑人更容易口头分享。
我推荐以下方法:
我应该承认,我不确定小块大小如何影响您的用例中密码的安全性。所以在你宣布这个防水之前,你可能想调查一下。
请注意,只需使用转换表,将随机促销代码与用户相关联,就可以很容易地以安全的方式进行操作。但是,这将违反您不需要修改数据库的要求。
隐藏 UserID 很容易。困难在于防止冲突:大多数短到易于通信或截断到该长度的散列函数将随机冲突。
这同样适用于加密函数:由于强加密会产生类似随机的密文,因此会因生日悖论而产生冲突。所以你需要的是一对一的转换。
一种方法是使用具有确定性和足够周期的 PRNG,并且仅使用其先前的编号作为状态,例如LFSR,其中 UserID 作为轮数。缺点是它可能很慢,除非用快速编译的语言编写。
一种更直接的方法是使用非常短的分组密码来加密该值。Skip32几乎可以毫不费力地实现。 Hasty Pudding更适合,因为它可以设置为 20 位块。
对于口头翻译,20-21 位转换为 7 个数字或 5 个 5 位字母数字和 2-5 个备用位。需要备用位作为错别字的校验位。如果您的用户群现在很小,您可以只使用这 2-5 位,并在您的用户群接近一百万时再添加一个校验位。
就个人而言,我更喜欢简短的字母数字而不是密码 - 后者会产生依赖记忆的诱惑,而人类记忆通常会用单词代替同义词。代码和数字更容易写下来,人们通常可以做到。OTOH,密码短语不需要校验位,因为其有限的字典本身就是校验位。这取决于您的用例和您的偏好。
所有这些方法都是不安全的;LFSR 甚至不是密码,其他两个相当弱。但是您的安全性受到邀请码的较短长度和保证避免碰撞的需要的限制。