首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >生成独特的、难以猜测的“优惠券”代码

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

Stack Overflow用户
提问于 2014-03-11 18:16:25
回答 7查看 17.2K关注 0票数 19

我的Rails应用程序需要为用户生成电子优惠券。每个优惠券应该有一个独特的优惠券代码,可以在我们的系统上赎回。

例如免费玉米煎饼的优惠券。User A收到免费玉米煎饼的优惠券,然后User B收到免费玉米煎饼的优惠券。这两张优惠券应该有唯一的优惠券代码。

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

我想,就像一张背面有一个独特号码的礼品卡一样,我正在寻找它。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2014-03-11 18:30:57

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

  • 这意味着,以该格式显示的所有可能代码的数量要远远大于要发出的代码数。根据简单地尝试代码(想想反复尝试的脚本)有多容易,那么您可能需要所有可能的代码才能比发出的代码多出100万或10亿或更多。这听起来很高,但在相对较短的字符串中是可能的。
  • 这也意味着您使用的代码必须在所有可能的代码中尽可能随机地选择。这对于避免用户发现大多数有效代码都以"AAA“开头是必要的。更复杂的用户可能会发现,您的“随机”代码使用了一个可黑客的随机数生成器(Ruby默认的rand()对随机数据具有快速和统计上的好处,但以这种方式是可破解的,所以不要使用它)。

这种安全代码的起点是密码PRNG的输出。Ruby有一个securerandom库,您可以使用它获取如下的原始代码:

代码语言:javascript
运行
复制
require 'securerandom'
SecureRandom.hex
# => "78c231af76a14ef9952406add6da5d42"

这段代码足够长,足以涵盖任何实际数量的代金券(地球上每个人都有数百万),没有任何有意义的重复机会,也不容易猜测。但是,从物理副本中输入是有点尴尬的。

一旦您知道如何生成一个随机的、几乎无法猜测的代码,您的下一个问题就是理解用户体验,并决定如何以可用性的名义实际地损害安全性。您需要记住对最终用户的价值,因此需要记住某人可能会多么努力地尝试获得有效的代码。我不能为你回答这个问题,但我可以提出一些关于可用性的一般性观点:

  • 避免含糊不清的字符。在打印中,有时很难看出1Il之间的区别。我们经常从上下文中理解它应该是什么,但是随机字符串的字符没有这个上下文。必须通过测试0O5S等测试代码的几个变体,这将是一种糟糕的用户体验。
  • 使用小写或大写字母,但不能同时使用。区分大小写将不会被理解或跟随的某些%的用户年龄。
  • 在匹配代码时接受变化。允许空格和破折号。也许甚至允许0O表达相同的意思。这是最好的处理输入文本,所以它是在正确的情况下,条形分隔符等。
  • 在打印中,将代码分成几个小部分,这样用户就更容易在字符串中找到自己的位置,并同时键入几个字符。
  • 不要把代码写得太长。我会建议12个字符,分为3组4。
  • 这里有一个有趣的问题--你可能想要扫描代码中可能出现的粗话,或者避免那些会产生它们的字符。如果您的代码只包含KUFC等字符,那么很有可能冒犯用户。这通常不是一个问题,因为用户看不到大多数计算机安全代码,但这些代码将在打印!

把所有这些放在一起,我就可以生成一个可用的代码:

代码语言:javascript
运行
复制
# Random, unguessable number as a base20 string
#  .rjust(12, '0') covers for unlikely, but possible small numbers
#  .reverse ensures we don't use first character (which may not take all values)
raw = SecureRandom.random_number( 2**80 ).to_s( 20 ).rjust(12, '0').reverse
# e.g. "3ecg4f2f3d2ei0236gi"


# Convert Ruby base 20 to better characters for user experience
long_code = raw.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有效代码,这意味着您可以发出10亿个您自己的代码,并且每四百万个用户中就有一个简单地猜测一个正确的代码。在密码学领域,这将是非常糟糕的(这段代码对快速的本地攻击是不安全的),但是对于向注册用户提供免费玉米煎饼的web表单来说,如果您注意到有人尝试了四百万次使用一个脚本,这是可以的。

票数 43
EN

Stack Overflow用户

发布于 2014-12-22 05:11:28

最近,我写了优惠券-代码宝石,它做了完全相同的事情。该算法借鉴算法::CouponCode CPAN模块。

优惠券代码不仅应该是唯一的,而且在仍然安全的情况下容易阅读和输入。尼尔的解释和解决方案很棒。这个gem提供了一种方便的方法来完成它,并提供了一个额外的验证功能。

代码语言:javascript
运行
复制
>> require 'coupon_code'
>> code = CouponCode.generate
=> "1K7Q-CTFM-LMTC"
>> CouponCode.validate(code)
=> "1K7Q-CTFM-LMTC"
>> CouponCode.validate('1K7Q-CTFM-LMTO') # Invalid code
=> nil
票数 9
EN

Stack Overflow用户

发布于 2015-12-04 14:44:14

创建不可猜测的优惠券码的关键是大空间的可能代码,其中只有一小部分实际上是有效的。让我们以8个字符长字母数字字符串为例:

字母数字= 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ - 63字符

在这种情况下,有63^8 = 248155780267521可能的代码。这意味着,如果你发布10亿个代码,那么猜测一个代码的概率将是百万分之一的10^9/63^8 = 0.000004... -4。

但是,它并不阻止运行一个脚本,直到找到一个有效的代码为止。为了阻止这样的蛮力攻击,您需要计算每个用户的尝试次数,并禁止超过某些限制。

如果您正在寻找一个允许对输出优惠券代码(长度、字符集、前缀、后缀和模式)进行完全定制的库,请查看凭单-代码生成器-js --一个用JavaScript编写的库。示例用法:

代码语言:javascript
运行
复制
voucher_codes.generate({
    length: 8,
    count: 1000,
});

它将产生1000个随机唯一的代码,每个8个字符长。

另一个例子是:

代码语言:javascript
运行
复制
voucher_codes.generate({
    pattern: "###-###-###",
    count: 1000,
});

它将根据给定的模式生成1000个随机唯一码。

源代码相对简单。我敢打赌,如果JS不是您最喜欢的语言,您可以轻松地将它重写为任何其他语言;)

如果您需要一个完整的凭证代码管理解决方案(包括暴力攻击预防),您可能对武彻化感兴趣。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22333237

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档