生成和保护礼品卡代码

10

我正在为一家公司工作,他们生成礼品卡代码,可以用于在线商店购买商品。

我想知道生成这些礼品卡代码最安全的方法是什么。长度需要为16个字符(尽管可协商),可以是字母数字混合的(数字会更受客户欢迎)。

从我所看到的,最安全的方法是使用以下Java代码生成特定长度的礼品卡代码:

static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static SecureRandom rnd = new SecureRandom();

String randomString( int len ){
   StringBuilder sb = new StringBuilder( len );
   for( int i = 0; i < len; i++ ) 
      sb.append( AB.charAt( rnd.nextInt(AB.length()) ) );
   return sb.toString();
}

这段内容摘自于stackoverflow的回答(这里)。我从字符串中删除了小写字母,以使其更加用户友好。因此,这产生了36 ^ 16个组合。仅数字将产生10 ^ 16个组合。我相信仅数字就足够了,但由于礼品卡欺诈日益普遍,通常强调字符串应为字母数字混合。

那么问题一是:数字还是字母数字混合?

当用户在在线商店使用礼品卡支付商品时,会调用我们的 API 返回该礼品卡的余额和货币类型。由于礼品卡代码是在第三方服务器上输入的,这些礼品卡现在对那些访问这些服务器的人可用。如果用户部分兑换后仍有余额,则显然存在问题。

其中一种选择是,在调用我们的API时(使用礼品卡代码获取余额),我们返回并在他们的商店上保存一个随机字符串,只有在线商店在向我们结算时才能使用 - 我们将在系统上与礼品卡代码匹配。问题在于,用户在结账时输入的礼品卡代码可能被记录在他们的日志中,并且可以被任何访问这些日志的人访问。

另一种选择是,在礼品卡部分兑换后刷新礼品卡代码。因此,用户实际上会获得一个新的礼品卡代码用于余额,而之前的代码将被取消。这可能是最安全的,但不太友好。

那么第二个问题是:我们如何保护仍具有价值的部分兑换的礼品卡代码?


@ErwinBolwidt 我会在security.stackexchange.com上发布这个问题。是的,这是一家只有3名开发人员的初创公司,所以我们可以自行决定这个问题。 - Mark
@RannLifshitz 是的,我正在考虑的解决方案之一是弃用原始密钥并为余额创建一个新密钥(在上面的问题中概述)。 - Mark
1
我希望我正确理解了您的概念。但是,我不会将诸如礼品码之类的信息发送到第三方服务器。我会使用像PayPal或Paysafecard这样的系统。如果用户想使用礼品卡支付某些东西,他将被转发到您的服务器以输入代码。然后,您将通知第三方付款是否成功。 - Lars
很遗憾,那不是一个选项。一个选项是在客户端浏览器上加密代码,当他们在在线商店输入后,将其发送到我们的服务器,返回某种密钥存储在在线商店上并与付款相关联。 - Mark
@Mark 你有控制在线商店吗?如果没有,这将没有太大帮助。在线商店仍然具有明文代码,不仅仅是加密版本。(另一个问题) 如果在线商店要求用户支付10美元。现在用户输入了价值50美元的代码。那么(邪恶的)商店可能会向您的服务器发送请求,使用用户输入的礼品码支付50美元。您无法验证该请求是否仅包含用户同意执行的操作。请在security.stackexchange.com上提出此问题,我非常期待看到解决方案。 - Lars
显示剩余6条评论
4个回答

3
所以你面临的问题很有趣。我读了@Therac解决方案,我同意他的看法,你最终会创建一个类似加密货币的协议。我也同意他所有的加密建议。
我不会重复@Therac的解决方案,但我会尝试通过解释一些加密货币的思路来帮助你。我不会进入太多技术细节,但从表面上看,你可以自己判断这个想法是否有价值。
因此,大多数加密货币使用的数据结构是默克尔哈希树。其想法是,将其作为交易的追加日志进行保留,以验证之前的交易并防止双重消费。
因此,有两种类型的交易。
1. 创建礼品卡代码 2. 消费礼品卡代码
仅当创建交易由您的公司签名时才有效。因此,您将存储您给出的金额、用户的公共地址(可能是他的帐户号码)和他的礼品卡代码。
第二种交易将是SpendGiftCode。这需要输入人的礼品卡代码,并要求他还签署交易以验证该交易来自他。SpendGiftCode会完全消耗礼品卡代码(销毁礼品卡代码并存储已使用),然后执行以下两个操作之一:
1.如果使用了全部金额,例如在一笔交易中完全使用了价值50美元的礼品卡,则会生成一个新的giftcardcode发送到他支付给的人的公共地址(即另一方的帐户号码)。
2.如果要使用的金额较少,例如从50美元中使用了10美元,则会生成两个giftcardcodes。其中一个价值10美元的礼品卡将发送给对方,而剩余金额的新giftcardcode将返回到他的帐户。
这将需要为您的用户和供应商创建帐户,但可以帮助减轻诸如双重支付和跟踪等问题。由于它是一个仅追加日志,因此您将能够跟踪每个供应商和用户进行的交易记录。Merkle哈希树允许在日志记录中进行优化。
当然,我没有深入探讨技术难点,并且我的解释中肯定存在一些情节漏洞,因为我试图提供一个广泛的概念性想法。如果您看到错误,请随时编辑。希望这对您有所帮助,祝愉快!

1
这是你在这里提出的一个不错的方法,但它很可能超出了产品的范围。 - Andrei Mărcuţ
1
@AndreiMarcut 我同意。但由于另一个论坛上已经有人给出了非常好的技术答案,我认为这个答案可能会激发一些想法。例如,在以太坊区块链之上构建系统并自己管理计算机节点(这也可能远离产品范围,并且会创建不必要的依赖关系)。我确实认为,2种交易类型模型的想法是可实现的。 - Haris Nadeem

1

我浏览了所有回复并得出了一个解决方案,考虑了所有建议:

我们会生成一个链接发送给用户。在链接中发送的密钥是一个随机的字母数字字符串,并且它被加密(MD5或类似的方式),因此在保存到数据库之前无法反向解密。
当用户单击链接时,他们将被重定向到我们的落地页,我们使用密钥获取订单,检查订单的状态和余额,如果一切正常,我们会生成一个16位字符长度的字母数字代码并发送到UI。这个16位字符代码再次被哈希(MD5),并保存在我们的数据库中。每次用户单击链接时,他们都会看到一个新的礼品卡代码,因为每次都是动态生成的。
在与在线商店的合同中,我们指定他们不能在任何地方记录或保存礼品卡代码(我们的两个客户是大型知名在线零售商)。
在我们客户的在线商店结账页面上,要使用我们的礼品卡代码付款,用户需要提供16位字符的礼品卡代码。它被发送到我们的服务器,余额和一个随机的付款ID返回到在线商店。该付款ID作为订单的一部分保存在在线商店上。订单完成后,在线商店会向我们的服务器发送API请求(带有付款ID),以从礼品卡中赎回金额(此功能由我们构建,并通过插件提供给在线商店安装)。
在线商店与我们的API之间的通信使用OAuth 2.0进行身份验证。
如果礼品卡上还有余额,将生成新的礼品卡代码(用户将收到一个新链接以获取其余额的新礼品卡代码)。
当在线商店向我们计费时,他们会向我们提供付款ID列表,然后我们将它们与后端中的礼品卡代码匹配(然后再与我们的发行者匹配)。

保护:

  • 礼品卡代码不会通过电子邮件发送,只有链接(在我们的后端,我们可以进行一些检查 - 如查看订单是否已过期,信用是否已经用完,然后才显示礼品卡代码)
  • 拥有在线商店数据库访问权限的人将无法看到我们的礼品卡代码
  • 已经黑客入侵我们的数据库的人也无法看到礼品卡代码(因为它们是散列的),也无法生成查看礼品卡代码的链接(因为链接的密钥也是散列的)

如果有任何评论,请告诉我。


1
考虑使用OAuth 2.0协议与JWT。在商店端使用OAuth对用户进行身份验证,并在令牌中提供有关余额的信息。不要提供任何礼品卡代码或任何重要个人信息。如果需要提供礼品码(用于客户调查),请生成一个以区分但不用于身份验证。当用户进行在线交易时,商店需要对其进行身份验证以接收实际余额。

1
针对第一个问题(数字或字母数字?)- 如果您关注安全性(我认为这应该是必须的),那么您需要增加编码字母表的复杂度,以便暴力破解/猜测攻击者需要更多的努力才能发现有效的礼品代码。通过增加可能性,猜测的概率会降低(但仍不是绝对安全的)。我建议使用字母(区分大小写)+数字。实际上,您更关心的是攻击者是否可以重复尝试猜测您的代码,而不是一次性随机猜测代码。为了防止这种情况,您可以利用现有的安全机制/概念,例如:(1)在(您的选择)1-2-3-5个失败的优惠券调用事件中,您可以引入指数重试延迟,以限制同一来源可以对您的API进行的连续攻击数量;(2)通过http重定向设置验证码机制,以防止在X(您的选择)个失败的API访问后机器人滥用。 < p >另外,由于您在相对较小的数字范围内使用随机函数,因此在向客户授予代码之前,您需要仔细检查新生成的代码的唯一性,以避免最终发生碰撞,从而使您的应用处于不想要的状态 < p >对于第二个问题,这更像是在选择安全机制之前做出的业务决策。如果您想保持优惠券服务,您可以为合作伙伴提供整个金额并让他管理余额,或者您可以在现有优惠券中保留剩余余额在自己的系统中,但面临合作伙伴泄漏您优惠码数据的风险,然后这将成为您的更大问题,或者您也可以发行另一个具有剩余余额的新优惠券(但是您必须面对将其与可能轻松分心的未知用户相关联的挑战),否则您必须管理用户财务帐户,这将使您成为不同的服务...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接