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();
}

这取自这里的 SO 答案。我从字符串中删除了小写字母以使其更加用户友好。所以这会产生 36 ^ 16 种组合。单独的数字将是 10 ^ 16 种组合。我相信仅数字就足够了,但人们经常强调,鉴于礼品卡欺诈的日益普遍,字符串应该是字母数字。

所以这是问题一:数字还是字母数字?

当用户在在线商店使用礼品卡支付商品时,会调用我们的 API,返回该礼品卡的余额和货币。鉴于礼品卡代码是在第三方服务器上输入的,这些礼品卡现在可供有权访问这些服务器的人使用。这在用户部分赎回后仍有余额的情况下显然是一个问题。

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

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

所以这是第二个问题:我们如何保护仅部分兑换并仍然具有价值的礼品卡代码?

4

4 回答 4

3

所以你面临的问题是一个有趣的问题。我阅读了@Therac对问题的解决方案,我不得不同意他的观点,即你最终会创建一个类似于加密货币的协议。我也同意他所有的密码学建议。

我不会重复@Therac 的解决方案,但是,我会通过解释加密货币的一些想法来看看我是否可以提供帮助。我不会详细介绍技术细节,但只是在肤浅的层面上,你可以自己判断这个想法是否适合你的用例。

所以大多数加密货币使用的数据结构是 Merkle 哈希树。这个想法是他们将其保留为仅附加的事务日志以验证先前的事务,并且它们不会被双重花费。

所以有两种类型的交易。

  1. 创建礼品码
  2. SpendGiftCode

创建交易只有在您的公司签字后才有效。因此,您将存储您提供的金额、用户的公共地址(可能是他的帐号)和他的礼​​品卡代码。

第二种交易将是 SpendGiftCode。这需要此人的礼品卡代码,并要求他还签署交易以验证交易来自他。

然后,SpendGiftCode 完全使用礼品卡代码(销毁礼品卡代码并存储它已被使用)并执行以下两项操作之一:

  1. 如果花费了全部金额,例如一张 50 美元的礼品卡完全用于交易,那么giftcardcode会在他正在付款的人的公共地址(即对方帐号)中生成一个新的。
  2. 如果要花费的金额较少,例如 50 美元中的 10 美元,则giftcardcodes生成两个。一个 10 美元的金额被发送给另一方,giftcardcode剩余金额的一个新的被发送回他的帐户。

这将需要为您的用户和供应商创建帐户,但可以帮助缓解双重支出和跟踪等问题。由于它是仅附加日志,因此您将能够跟踪每个供应商和用户进行的交易。merkle哈希树允许对日志保存进行优化。

当然,有几层技术困难我没有深入研究,而且我的解释中当然存在一些情节漏洞,因为我试图提供一个广泛的概念性想法。随意编辑您可能看到错误的任何地方。希望这对您有所帮助,

干杯!

于 2018-04-07T06:32:56.140 回答
1

考虑将 OAuth 2.0 协议与 JWT 结合使用。使用 OAuth 在商店端对用户进行身份验证,并在令牌中提供有关余额的信息。不要提供任何礼品卡代码或任何重要的个人信息。如果您需要提供礼品代码(用于客户调查),请生成任何只是为了区分但不要将它们用于身份验证。当用户在网上商店进行交易时,需要对其进行身份验证才能收到实际余额。

于 2018-04-10T06:15:48.123 回答
1

我浏览了所有回复并提出了解决方案,并考虑了以下建议:

  • 我们生成一个链接发送给用户。链接中发送的密钥是一个随机的字母数字字符串,它是经过散列的(MD5 或类似的),因此在保存到数据库之前无法撤销。

  • 当用户点击链接时,他们会被重定向到我们的登陆页面,我们使用 key 获取订单,检查订单状态以及是否有信用,如果可以,我们生成一个 16 字符长度的字母数字代码和发送到 UI。16 个字符的代码经过哈希处理(同样是 MD5)并保存在我们的数据库中。每次用户点击链接时,他们都会看到一个新的礼品卡代码,因为它每次都是动态生成的。

  • 在与在线商店的合同中,我们指定他们不能在任何地方记录或保存礼品卡代码(我们的 2 个客户是大型知名在线零售商)

  • 在我们客户的在线商店结帐页面上,使用我们的礼品卡代码付款时,用户提供了 16 个字符的礼品卡代码。它被发送到我们的服务器,余额和一个随机支付 ID 被返回到在线商店。此付款 ID 作为订单的一部分保存在在线商店中。订单完成后,在线商店向我们的服务器发送 API 请求(带有支付 ID),以从礼品卡中兑换金额(此功能由我们构建,并通过他们安装的插件提供给在线商店)。

  • 在线商店和我们的 API 之间的通信使用 OAuth 2.0 进行身份验证

  • 如果礼品卡上还有余额,则会生成一个新的礼品卡代码(向用户发送一个新链接以获取余额的新礼品卡代码)

  • 当在线商店向我们收费时,他们会向我们提供付款 ID 列表,然后我们将其与后端中的礼品卡代码进行匹配(然后与我们的发行人匹配)。

保护:

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

让我知道是否有任何意见。

于 2018-04-30T14:20:50.313 回答
1

对于第一个问题(数字还是字母数字?) - 如果您关注安全性(我认为应该是这种情况),那么您希望增加编码字母表的复杂性,以便暴力/猜测攻击者拥有花费更多精力来发现有效的礼品代码

通过增加可能性的数量,猜测的概率会降低(但它仍然不是防弹的)

我建议使用alpha(区分大小写)+ 数字

实际上,如果攻击者可以反复尝试猜测您的代码,而不是一次性随机猜测代码,您会更关心这里

为了防止这种情况,您可以利用现有的安全机制/概念,例如:

(1) 如果(您的选择)1-2-3-5 次优惠券调用失败,您可以引入指数重试延迟,以限制同一来源可能在您的 API 上安装的连续攻击数量

(2) 通过 http 重定向设置验证码机制,以防止机器人在 X(您的选择)API 命中失败后滥用

此外,由于您在相对较低的数字范围内使用随机函数,因此在将代码授予客户之前,您需要根据数据库仔细检查新生成代码的唯一性,以避免最终发生冲突可能会使您的应用程序处于不需要的状态

对于第二个问题,这听起来更像是选择安全机制之前的业务决策。如果您想保留优惠券服务,您可以为合作伙伴提供全部金额并让他管理余额,或者您可以将剩余余额保留在您自己的系统中的现有优惠券上,但合作伙伴可能会泄露您的优惠券代码数据那么这对您来说将是一个更大的问题,或者您也可以使用剩余余额发行另一张新优惠券(但随后您将面临将其与可能很容易从该流程中分心的未知用户关联的挑战)否则您会必须管理用户财务帐户,这会将您变成不同的服务..

于 2018-04-11T17:07:24.520 回答