Hash

散列信用卡號碼以使用散列作為指紋的最安全替代方案?

  • April 2, 2020

2014 年在這裡提出了同樣的問題,但自那以後發生了很多變化,我想從專家那裡獲得有關最新最佳實踐的回饋。

問題

我們的要求是為商戶提供唯一標識卡號的**卡指紋。**通過使用這個指紋,商家可以檢查,例如,她的兩個客戶是否正在使用同一張卡,或者更有趣的是,如果不是已知的卡所有者的人即將使用它。

我們的目標是根據 John Downey 的回答(已接受的答案)在這裡使用 Braintree 使用的相同策略,我引用:

“在 Braintree API 中,我們為信用卡提供了唯一的數字標識符。這個標識符是一個隨機的不透明令牌,對於儲存在我們系統中的卡號,它總是相同的。這個數字的種子在我們系統中每個商家都不同,因此您無法在商家之間進行比較。

當一張新卡進來時,我們通過將其與散列 + 加鹽列進行比較來查找它。如果它與現有列匹配,我們知道我們可以返回相同的唯一編號標識符。如果它不匹配任何現有記錄,我們會使用加密安全的偽隨機數生成器來創建一個新的唯一編號標識符,並確保它不會與現有的標識符衝突。

通過這種方式,雜湊 + 加鹽值永遠不會離開我們的後端,但我們仍然可以為商家提供一種方法來唯一地辨識儲存的信用卡。”

編輯:

正如@mentallurg 所指出的,指紋計算應該盡可能快並且不包含秘密組件。這種情況下的問題是它也應該是不透明和安全的,因為我們只能用卡號來計算它(不像設備有幾個參數,如作業系統、版本、品牌、mac 地址等)。並非總是提供持卡人姓名,如果更換實體卡,卡的到期日期可能會發生變化,因此我們無法使用它們。因此,僅使用卡號計算快速指紋並將該指紋提供給客戶端不是一種選擇。

剩下的選擇是使用加密散列函式。通過對卡號進行安全雜湊處理,我們可以確定生成相同雜湊的兩個卡號實際上是相同的卡,從而滿足我們的要求。向商家提供散列本身仍然不安全,這就是為什麼我們生成一個隨機安全字元串並將其與實際散列相關聯,這樣,當一張新卡進來時,我們對其進行散列,如果它與已經存在的卡匹配我們可以將隨機指紋(無法從中檢索到卡數據)返回給商家,而不會暴露實際的雜湊值。如果沒有匹配,那麼我們會生成一個新的隨機指紋,確保它不會與現有指紋發生衝突並將其返回給商家。

出現的下一個問題是使用什麼加密雜湊函式/策略。必須對卡號加鹽以防止彩虹表攻擊,這裡的鹽的問題是它們會導致相同卡號的兩個實例生成不同的雜湊(這實際上是處理密碼時的一件好事,因為你不’不希望兩個相同的密碼生成相同的雜湊)這使得它對我們的要求沒有用處。

到目前為止,我們能想到的最佳選擇是使用強大的加密雜湊函式(針對安全性和性能之間的適當折衷進行調整)並使用唯一的 HSM 支持的密鑰(或者如果我們使用每個商家的密鑰)對其進行加鹽。想要每個商家的雜湊值)。

我們知道保存卡號的所有 PCI 含義。到目前為止,我們已經考慮了以下替代方案:

  1. 使用 HMAC,將商家特定密鑰用作秘密加密密鑰。對於加密雜湊函式,我們必須使用加密安全的函式,所以我們選擇了 SHA3,但後來我們意識到 SHA3 在設計上可以充當 HMAC,正如這裡所解釋的,不需要 HMAC 嵌套結構。
  2. 使用 SHA3 對使用商家特定密鑰加鹽的卡號進行雜湊處理。這似乎是一個不錯的選擇,只要使用最強版本的 SHA3 和足夠長的密鑰。但是,如果數據庫被盜,我們擔心的是暴力攻擊。經過一些研究,我們發現重新散列生成的雜湊 n 次將有助於使攻擊者的任務變慢,並且在最好的情況下,只要它不減慢我們的服務速度,甚至是不可行的。所以我們去嘗試並重新散列我們的雜湊 n 次。但是後來我們很好奇重新散列究竟是如何提高安全性的,並發現即使重新散列本身是一個好主意,實現您自己的非標準散列模式,卻不了解這樣的方案需要什麼特性才能成為安全的, 不是。更好的選擇是採用一種通過設計重新散列的散列算法,如 PBKDF2、Scrypt 或 Argon2id。
  3. 使用 PBKDF2 從使用商戶特定密鑰加鹽的卡號中導出密鑰,設置大量迭代並選擇 SHA3 作為雜湊函式。
  4. 使用密碼散列競賽的目前獲勝者和推薦的 Argon2id,並為timememorythreads提供適當的參數,但我們尚不確定如何正確調整這些參數。閱讀您對如何操作的評論將非常有幫助。

我們在選項 3 和 4 之間進行辯論,一方面 PBKDF2 似乎使用更廣泛,但另一方面有一些資源聲稱它對於今天的硬體容量不再安全,並強烈推薦使用 Argon2id。

那麼,您會在這種情況下使用什麼策略呢?您在以前的選項中看到了哪些缺陷?你會選擇 PBKDF2 還是 Argon2id?您能找到其他安全提供卡指紋的方法嗎?

此類問題有基於意見的答案。這是我的意見。

首先檢查您的要求並檢查您實際想要實現什麼,如果您想使用密鑰派生(特定散列需要多少硬體)的成本是多少,如果您不使用散列有什麼風險。

你說你想用卡號作為指紋。指紋不必抵抗計算。反之亦然:指紋的計算應該盡可能快。它還應該具有低碰撞率。這就是為什麼經常使用 SHA256 和類似的快速算法的原因。

像 PBKDF2 和 Argon2id 這樣的算法有完全不同的目的。即,提供秘密資訊的(可能)唯一表示,並防止通過暴力破解檢索該資訊。

對我來說這是一個矛盾:您想使用密鑰派生算法進行指紋辨識。

然後你在談論商家密鑰。這又與指紋一詞相矛盾。指紋不應包含任何秘密成分。應該是每個人都可以隨時計算和檢查的。

如果您的意思實際上是密鑰派生,而不是指紋,並且想要保存卡號而不洩露它們,那麼我建議您檢查它是否對您的情況有意義。因為暴力破解卡號並不難。前 4 位數字標識卡系統,不是隨機的。一位是校驗和,也不是隨機的。其餘的 11 位數字也可以根據銀行也不是隨機的。但是讓我們假設它們是隨機的。

11 位數字的安全性如何?11 位表示 37 位。猜測這樣的數字近似於猜測由大小寫字母和數字組成的 6 個字元的密碼。具有大約 90 位熵的密碼被認為是安全的。

我假設您的應用程序在具有普通 CPU 的硬體上執行。我假設您的客戶會接受大約 1 秒的延遲,而不是 1 分鐘和 1 小時。假設攻擊者使用的 GPU 比你的 CPU 快 100 倍。一天有 86 400 秒。因此,攻擊者每天可以在每個 GPU 上測試 8 640 000 個數字。檢查他需要的所有 11 位數字 $ 10^{11} / (8 640 000) = 11574 $ 天。對於擁有 100 個 GPU 的小型家庭農場,需要 115 天。對於擁有 10 000 個 GPU 的更大農場,這將只需要大約一天的時間。如果有足夠的 RAM,這是正確的。

假設您想為每個散列/密鑰派生使用更多 RAM。你能用多少?想想您希望同時處理多少個請求以及您有多少 RAM。如果您想通過卡雜湊計算支持 1000 個同時請求並且您有 128 GB RAM,那麼顯然每個雜湊可以使用不超過 128 MB。如果您的應用程序需要大部分 RAM 用於其他目的,那麼對於散列,您將擁有更少的 RAM。這意味著攻擊者也需要更少的 RAM。

這就是為什麼我再次建議您審查您的要求並決定您的實際目標是什麼。

對於其他問題: PBKDF2 和 Argon2 的比較已經在 StackExchange 上討論過廣泛使用並不總是一個好的論據,例如考慮 MD5。在許多情況下,仍然可以使用 MD5。但是,如果雜湊衝突的後果代價高昂,則應該使用其他算法。

對於參數的調整,請考慮以下約束:

  • 您的使用者可以接受的最大響應時間是多少?
  • 您需要同時支持多少個請求?
  • 您需要同時支持多少個雜湊請求?
  • 您需要多少 CPU 和 RAM?
  • 對於維護它的員工,硬體/雲的可用預算是多少?

如果您計算並與您的商家或產品所有者討論,他們可能會認為成本遠高於擁有他們想要的功能的可能收益(檢查是否在其他情況下使用信用卡)。

所有的 PCI 合規性方面都是已知和涵蓋的,我們現在關注的是散列部分。

鑑於令牌化PCI 的一部分,我認為您確實沒有“所有已知和涵蓋的 PCI 合規方面”。PCI 提供有關標記化的指南。你應該閱讀它們。

可能最明智的選擇是將 HKDF 與 HSM 支持的密鑰一起使用。salt可以通過使用每個商家參數來處理每個商家的唯一令牌。請做理智的事情,並在 HSM 上完成這一切。如果攻擊者知道密鑰,那麼暴力破解整個搜尋空間是微不足道的。

引用自:https://crypto.stackexchange.com/questions/79587