一尘不染

生成难以猜测的独特“优惠券”代码

algorithm

My Rails应用程序需要为用户生成电子优惠券。给定的每个优惠券都应具有唯一的优惠券代码,可以在我们的系统上兑换。

例如,免费墨西哥卷饼的优惠券。User A接收免费卷饼User B的优惠券,然后接收免费卷饼的优惠券。2张优惠券应具有唯一的优惠券代码。

生成像这样不容易伪造的代码的最佳方法是什么?我不希望用户输入随机数字和兑换其他人的优惠券的成功率很高。

我想我想找的是像背面有唯一编号的礼品卡。


阅读 192

收藏
2020-07-28

共1个答案

一尘不染

该代码必须不可猜测,因为在给用户奖励之前,您可以执行的唯一验证就是检查他们输入的代码是否在“已发布”代码列表中。

  • 这意味着该格式中所有可能的代码数量远大于您要发布的代码数量。根据尝试代码的难易程度(例如脚本反复尝试),您可能需要所有可能的代码才能使已发布的代码数超过一百万或十亿甚至更多。听起来不错,但是在相对较短的琴弦中是可能的。

  • 这也意味着必须在所有可能的代码中尽可能随机地选择您使用的代码。避免用户弄清楚大多数有效代码都以“ AAA”开头是必要的。更老练的用户可能会发现您的“随机”代码使用了可破解的随机数生成器(Ruby的默认设置rand()是快速的,并且在统计上对随机数据非常有用,但是以这种方式可破解,因此请不要使用它)。

此类安全代码的起点是加密PRNG的输出。Ruby拥有该securerandom库,您可以使用该库来获取如下原始代码:

require 'securerandom'
SecureRandom.hex
# => "78c231af76a14ef9952406add6da5d42"

该代码足够长,可以覆盖任何实际数量的代金券(每个星球上每个人都有数百万个代金券),而没有任何有意义的重复机会或容易猜测的机会。但是,从物理副本键入内容有点尴尬。

一旦知道了如何生成随机的,几乎无法猜测的代码,您的下一个问题便是了解用户体验,并决定以可用性的名义实际损害安全性的程度。您需要牢记最终用户的价值,因此要记住有人可能会努力获取有效代码。我不能为您回答这个问题,但是可以针对可用性提出一些一般性的观点:

  • 避免使用不明确的字符。在打印时,有时很难看出之间的差1Il例如。我们经常从上下文中了解它应该是什么,但是随机的字符串不具有此上下文。必须通过测试0vs O5vs S等尝试多种代码变体,这将是糟糕的用户体验。

  • 使用小写或大写字母,但不能两者都使用。区分年龄的用户不会理解或区分大小写。

  • 匹配代码时接受变化。允许有空格和破折号。也许甚至允许0O表示相同的意思。最好通过处理输入文本来做到这一点,以便在正确的情况下使用带分隔符的字符等。

  • 在打印中,将代码分成几个小部分,用户可以更轻松地找到他们在字符串中的位置并一次输入几个字符。

  • 不要使代码太长。我建议以3组为一组,每组12个字符。

  • 这是一个有趣的问题-您可能希望扫描代码中可能存在的粗鲁单词,或者避免使用会生成粗鲁单词的字符。如果你的代码只包含文字KUFC,那么就不会有得罪用户的机会很高。通常不需要担心,因为用户看不到大多数计算机安全密码,但是这些密码会打印出来!

综上所述,这就是我可能生成可用代码的方式:

# Random, unguessable number as a base20 string
#  .reverse ensures we don't use first character (which may not take all values)
raw_string = SecureRandom.random_number( 2**80 ).to_s( 20 ).reverse
# e.g. "3ecg4f2f3d2ei0236gi"


# Convert Ruby base 20 to better characters for user experience
long_code = raw_string.tr( '0123456789abcdefghij', '234679QWERTYUPADFGHX' )
# e.g. "6AUF7D4D6P4AH246QFH"


# Format the code for printing
short_code = long_code[0..3] + '-' + long_code[4..7] + '-' + long_code[8..11]
# e.g. "6AUF-7D4D-6P4A"

20**12这种格式的有效代码,这意味着您可以发布十亿个自己的代码,而用户仅猜测正确的代码就有四百万分之一的可能性。在密码学界,这是非常糟糕的(此代码对于快速的本地攻击是不安全的),但是对于向注册用户提供免费卷饼的网络表单,您会发现有人尝试使用脚本进行四百万次,这没关系。

2020-07-28