有没有一种安全的方法来保证信用卡的唯一性?
因此,就像任何相当有能力的网络开发商店一样,我们在接触信用卡时会戴上棉手套,并使用 Braintree SecureVault 来存储它们,这样我们就不会遇到 PCI 合规性问题。
然而,现在我们希望为我们的服务提供免费试用,这在很大程度上依赖于能够保证给定的信用卡在免费试用中仅使用一次。理想情况下,我们能够对信用卡号本身进行哈希处理以保证唯一性。问题是有效的信用卡号码集很小,因此很容易暴力破解信用卡号码。据我所知,加盐策略毫无用处,因为如果有人可以访问哈希数据库,他们很可能也拥有代码,从而拥有加盐算法。
到目前为止最好的两个想法是:
A)将哈希值隔离在一个集合中,与其计费信息无关。因此,如果哈希值是暴力破解的,那么他们所拥有的只是在某个时间点使用过的信用卡号码列表,没有个人信息,也不知道它是否仍然有效。这里的主要弱点是我们确实有最后四强的记录,这可能会在某种程度上用来匹配它们。
B) 没有完整数字的哈希并处理误报和漏报。名称、last-4 和过期时间的哈希值应该是相当独特的。误报就像中了彩票一样,我们可以通过客户支持来处理。修改名称可能会导致漏报,我们不清楚我们对名称匹配的精度有何保证(据我了解,可能受到网关和商家帐户的影响),因此这可能会造成漏洞。
想法?建议?久经考验的智慧?
So, like any reasonably competent web development shop, we wear cotton gloves when we touch credit cards, and we use Braintree SecureVault to store them so we are clear of PCI Compliance issues.
However now we want to offer a free trial for our service, which pretty much relies on being able to guarantee that a given credit card is only used once for a free trial. Ideally we would be able to hash the credit card number itself to guarantee uniqueness. The problem there is that set of valid credit card numbers is small, so it's going to be easy to brute force the credit card numbers. Salting tactics are useless as far as I can see, because if someone has access to the database of hashes, they will most likely have the code as well, and thus the salting algorithm.
The best two ideas so far are:
A) Keeping the hashes isolated in a set, with no relation to their billing information. Therefore if the hashes are brute-forced, all they have is a list of credit card numbers that were used at some point in time, with no personal information or knowledge of whether it's even still valid. The main weakness here is that we do have record of the last-4 which could potentially be used to match them up to some extent.
B) Hash without the full number and deal with the false positives and negatives. Hashing on name, last-4 and expiration ought to be fairly unique. False positive is like winning the lottery, we can deal with it at customer support. False negative could be induced by modifying the name, we are not clear on what assurances we have about the precision of name matching (potentially affected both by the gateway and merchant account is my understanding), so this could open a loophole.
Thoughts? Suggestions? Battle-tested Wisdom?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
高级:使用现有的支付系统
我认为这种方法——使用信用卡号来确定用户是否已经利用了免费试用并且没有资格获得后续的免费试用——是误导的。首先,您会通过预先要求信用卡(许多用户不会提供信用卡,除非他们真正准备好购买)而不是在试用期结束后才要求信用卡来赶走潜在客户。
其次,你正在重新发明轮子。有大量的“应用程序商店”(Chrome 网上商店、Android 市场、iTunes 应用程序商店等)提供内置的付款和试用期机制。使用这些系统将提高您的产品对消费者的可见度,为您的潜在客户提供多种不同的支付方式(使他们更倾向于购买),并且还可以省去您自己实施此机制的麻烦。另外,用户通常更愿意将信用卡发放给尽可能少的公司;您不仅必须自己实现这个复杂的机制,而且还必须让用户足够信任您才能使用它。
较低级别:实施细节
任何哈希机制都可能发生冲突,因此您仍然需要处理这个问题。显然,您应该对服务器使用全磁盘加密和其他最佳安全实践。通过将后端数据库服务托管在与托管此代码的计算机不同的计算机上,可以降低数据库和加盐算法同时受到损害的风险。哈希的主要漏洞是暴力攻击。对付它们的最好方法就是让暴力破解的成本足够高,以至于不值得攻击者花时间。对每个条目使用单独的盐(例如,客户的姓名、客户的邮政编码等作为盐的一部分)将使使用彩虹表变得无效。当然,降低数据本身对攻击者的价值(例如不包括完整的信用卡号)也是阻止此类攻击的好方法。无论如何,我再次建议您利用许多应用程序商店,而不是自己实现。
High-level: Use Existing Payment Systems
I think that this approach -- using credit card numbers to determine if a user already has taken advantage of a free trial and should be ineligible for a subsequent free trial -- is misguided. Firstly, you will drive away potential customers by requiring a credit card upfront (which many users don't give out unless they are actually ready to buy), instead of requiring it only after the trial period has ended.
Secondly, you are reinventing the wheel. There are a plethora of "app stores" (the Chrome webstore, the Android marketplace, the iTunes app store, etc.) which provide builtin mechanisms for payment and trial periods. Using these systems will give your product increased visiblity to consumers, will offer your potential customers multiple different payment methods (making them more inclined to buy), and will also save you the hassle of implementing this mechanism yourself. Plus, users generally prefer to give out their credit card to the least number of companies possible; not only would you have to implement this complex mechanism yourself, but you would also have to get users to trust you enough to use it.
Lower-level: Implementation Details
Any hash mechanism can have collisions, hence you would still need to deal with this problem. You should obviously use full disk encryption and other best security practices with your servers. The risk of having both the database and the salting algorithm compromised at the same time can be reduced by hosting the backend database service on a separate machine from the one that hosts this code. The main vulnerability of hashing is brute force attacks. And the best way to deal with them is to just make brute forcing expensive enough that it isn't worth the attacker's while. Using a separate salt for each entry (e.g. the customer's name, the customer's zip code, etc. as part of the salt) will make using rainbow tables ineffective. Of course making the data, itself, less valuable to attackers (e.g. not including the full credit card number) is also a good way to discourage these kinds of attacks. In any case, I again advise you to take advantage of the many app stores instead of implementing this yourself.
如果我错过了什么,请原谅我,但是为什么你不能只拥有一个只有一列的“UsedCreditCards”表,该列是信用卡号的 SHA512 哈希值,也许还有到期日期。这是无法逆转的,通过将其保存在另一个表中并且不存储有关该代码的任何其他数据,您可以轻松检查信用卡号是否已被使用过。
我不确定这是否会违反 PCI 或其他任何规定(我不这么认为,但我可能是错的)
Forgive me if I missed something, but why can't you just have a table of "UsedCreditCards" that just has a single column, which is a SHA512 hash of the credit card number and maybe the expiration date. This could not be reversed, and by keeping it in another table and not storing any other data about the code, you could easily check to see if a credit card number has been used before.
I am not sure if this would violate PCI or anything (I don't think so, but I could be wrong)