My Rails应用程序需要为用户生成电子优惠券。给定的每个优惠券都应具有唯一的优惠券代码,可以在我们的系统上兑换。
例如,免费墨西哥卷饼的优惠券。 User A
收到免费卷饼的优惠券,然后User B
收到免费卷饼的优惠券。 2张优惠券应具有唯一的优惠券代码。
生成像这样不容易伪造的代码的最佳方法是什么?我不希望用户输入随机数字和兑换其他人的优惠券的成功率很高。
我想我想找的是像礼品卡,背面有一个唯一的编号。
最佳答案
该代码必须不可猜测,因为在给用户奖励之前,您可以执行的唯一验证就是检查他们输入的代码是否在“已发布”代码列表中。
rand()
快速且统计上适用于随机数据,但是可以通过这种方式进行破解,因此请不要使用它)。 此类安全代码的起点是加密PRNG的输出。 Ruby有
securerandom
库,您可以使用它来获得如下原始代码:require 'securerandom'
SecureRandom.hex
# => "78c231af76a14ef9952406add6da5d42"
该代码足够长,可以覆盖任何实际数量的代金券(每个星球上每个人都有数百万个代金券),而没有任何有意义的重复机会或容易猜测的机会。但是,从物理副本中键入内容有点尴尬。
一旦知道了如何生成随机的,几乎无法猜测的代码,您的下一个问题便是了解用户体验,并决定以可用性的名义实际上可以危及安全的程度。您需要牢记最终用户的值(value),因此要记住有人可能会努力获取有效代码。我不能为您回答这个问题,但是可以针对可用性提出一些一般性观点:
1
,I
和l
之间的区别。我们通常会从上下文中了解它应该是什么,但是随机字符串不具有此上下文。必须通过测试0
与O
,5
与S
等来尝试几种代码变体,这将是糟糕的用户体验。0
和O
表示同一意思。最好通过处理输入文本来做到这一点,以便在正确的情况下使用带分隔符的字符等。K
,U
,F
,C
字符,那么冒犯用户的可能性就很大。通常不需要担心,因为用户看不到大多数计算机安全密码,但是这些密码会打印出来! 综上所述,这就是我可能生成可用代码的方式:
# 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
有效代码,这意味着您可以发布十亿个自己的代码,而用户仅猜测正确的代码就有四百万分之一的可能性。在密码学界,这是非常糟糕的(此代码对于快速的本地攻击是不安全的),但是对于向注册用户提供免费卷饼的网络表单,您会发现有人尝试使用脚本进行四百万次,这没关系。
关于ruby-on-rails - 生成独特的,难以猜测的 “coupon”代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22333237/