生成和保护礼品卡代码

信息安全 哈希 爪哇 电子商务
2021-08-27 17:13:55

我正在为一家生成礼品卡代码的公司工作,该代码可用于在网上商店购买商品。

我想知道生成这些礼品卡代码的最安全方法是什么。长度需要为 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();
}

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

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

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

另一种选择是我们在部分兑换后刷新礼品卡代码。因此,用户基本上会获得余额的新礼品卡代码,而之前的礼品卡代码将被取消。这可能是最安全的,但不是那么用户友好。所以这是第二个问题:我们如何保护仅部分兑换并仍然具有价值的礼品卡代码?

编辑:

我们还有一个检查余额页面,用户输入礼品卡代码并返回货币和余额。这可能会产生一些额外的安全问题。

4个回答

为了防止欺诈,您需要足够低的攻击者猜测任何有效代码的概率。对于 100 万张卡片,平均每 10^10 次尝试猜测 10^16 个代码。如果您的网站是完全安全的,并且您的 API 具有蛮力抗性,那么 numeric 应该足以使这种欺诈方法不具有成本效益。

但是它的安全性非常脆弱,下面的哈希保护在这么小的密钥空间的数据库泄漏中很容易被破解。IOW,有权访问您的数据库的攻击者将能够暴力破解许多有效代码。字母数字代码将提供更强大的安全性。您也可以使用一种用户友好的模式来妥协。

由于在您的系统中代码实际上既是登录名又是密码,为了减少它们的泄漏,您需要更改通信协议以消除明文代码的传输和存储。

最简单的协议是存储 Salt1 和 SaltHash1=hash(Code+Salt1),然后将 Salt1 传输到客户端,在客户端创建 Salt2,在客户端生成 hash(hash(Code+Salt1)+Salt2) 并检查它针对哈希(SaltHash1+Salt2)。

如果您的数据库遭到破坏,这仍然很容易受到攻击,因为攻击者只需要一个有效的 SaltHash1 列表即可通过您的 API 进行购买。它也很慢,因为您必须散列所有有效代码才能检查一个。

为了使其更健壮,您可以使用像 Argon2id 这样的 PBKDF 转换所有代码,这是一个缓慢且不可逆的函数,并且只存储结果。使用慢速函数可确保拥有泄露数据库的攻击者无法轻易暴力破解所有 10^16 代码以找到所有适合的代码并模拟合法用户。您仍然必须相信商店不会存储代码并强制执行 HSTS(仅限 https)连接。

不可能使这个系统免受记录用户输入的流氓商店的影响——如果他们有完整的代码,他们就拥有这张卡。唯一的防御是只允许通过直接从您的服务器加载的表单(它可以嵌入到第三方页面中)进行代码兑换。如果您这样做,除了用户和您的 PBKDF 之外,没有人会看到代码;商店只会收到您的验证回复。

鉴于礼品卡代码是在第三方服务器上输入的,这些礼品卡现在可供有权访问这些服务器的人使用。

确实,服务器管理员可以访问礼品卡,但他们也可以访问用户在在线商店中输入的信用卡号。如果您可以信任在线商店收集信用卡号码而不做任何恶意行为,那么您为什么不能也信任他们收集礼品卡 ID?(或者您可能认为,当管理员窃取 CC 号码时,这不是您的问题,但如果他们窃取礼品卡代码,那是您的问题……)也许正确审查您的商家需要成为您商业模式的一部分。

您在每次购买后更改礼品卡代码的想法应该可行,但是您如何告诉用户他们的新代码是什么?也许您可以通过电子邮件通知他们交易,包括他们的余额,并提供一个链接让他们登录并获取他们的新礼品卡 ID。不过我同意,这对某些用户来说可能有点烦人。这实际上取决于商家的可信度,而用户可能最了解。也许您可以允许用户决定是否要启用重置选项,甚至可以允许他们设置一个阈值,高于该阈值(例如 50 美元)。

我相信有一个基本问题是你无法从技术上解决的。大多数已建立的反欺诈措施都会降低风险,但您必须接受欺诈将会发生。

这基本上是一个信任问题。您相信商店会为每笔交易从礼品卡中扣除正确的金额,并且只发布用户授权的交易。您还相信用户会为卡保密。

信任问题需要审计。与信用卡一样,第 3 方也有可能滥用信用卡。许多关于信用卡的 PCI DSS 规则旨在最大限度地降低欺诈风险,但即使有这些规则,信用卡行业也面临着重大的欺诈风险。为了解决这种风险,银行会监控欺诈迹象,并向持卡人提供对账单,以便他们还可以查看账户活动是否存在未经授权的交易。您无法消除欺诈风险,因此您必须监控和报告活动——并允许用户这样做。

警惕和响应是唯一的长期解决方案。尽管采取了合理的安全措施,您仍无法完全防止欺诈。如果这是可能的,信用卡行业每年将节省数十亿美元。他们做不到,你的公司可能也不会。您的公司和用户必须注意滥用行为并根据需要采取纠正措施。如果您的公司发行礼品卡,他们必须承诺在该计划的整个生命周期内配备反欺诈人员。即使您不提起法律诉讼,您也需要为您的用户提供补救措施。必须授权某人调查和裁决欺诈索赔。

您可以实施既定的安全措施。大多数礼品卡以零余额开始,和/或它们在售出之前处于非活动状态。帐号或 CVV 在售出前应隐藏(密封在防篡改包装中或在刮擦后)。在销售点,激活是基于序列号而不是礼品卡 ID — 并且礼品卡 ID 不会以任何可辨别的方式从该序列号派生,反之亦然。

秘密是共享的,这破坏了大多数安全性。使用礼品卡和传统信用卡,用户向第三方卖家提供冒充他们所需的一切。这与允许用户保密的基于区块链的系统形成鲜明对比。当您处理一个根本不安全的系统时,您必须针对这些风险实施补偿控制或缓解措施。然后你接受任何风险并继续前进。

在信用卡世界中,客户在浏览器中输入卡号的每笔在线交易都需要卡号CVV2 代码。这通常是印在卡背面的 3 位数代码。建议商户切勿存储此号码,但可以保留卡号(在非常严格的限制下)。

类比是卡号就像用户名,而 CVV2 就像密码(有点,也许!)。您的问题似乎是您仅依赖卡号,这就像仅出于安全性而依赖用户名一样。这是一个问题,应该有某种方式来验证卡,卡号只是一个标识符。

我的建议是在交易中添加某种 PIN。客户必须在 API 调用中提供 PIN 才能获得批准。该 PIN 绝不能存储在商家日志中。如果您对此感到担心,请尝试创建一个一次性 PIN (OTP),以便在进行交易时向客户发送短信,但这会增加大量复杂性,但也消除了商家重复使用的风险另一笔交易的卡——因为他们永远不会有 OTP。

更改卡号是一件更加困难的事情——而且可能不是最好的客户旅程,我不建议这样做。