簡體   English   中英

SHA 算法每次為相同的密鑰生成唯一的哈希字符串

[英]SHA algorithm generates each time unique hash string for a same key

我知道有很多關於散列和加密算法的文章。

我從他們那里弄清楚使用散列函數而不是加密將密碼存儲在數據庫中

所以我決定使用 SHA-256 算法來生成散列密鑰,並將該散列密鑰存儲到我的服務器數據庫中,而不是普通密碼。

現在我真的無法理解我應該如何使用它,因為每次我傳遞相同的密碼來生成 SHA 密鑰時,它都會給我與以前不同的密碼,而不是我如何將它與數據庫中存儲的哈希密鑰進行比較?

我正在使用 java 所以我的 java 代碼是

public class Test {
public static void main(String...arg) throws IOException{
    System.out.println("First time");
    String string64 = getEncryptedPassword("FenilShah");
    System.out.println(string64);
    System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(string64)));

    System.out.println("\nSecond time");
    string64 = getEncryptedPassword("FenilShah");
    System.out.println(string64);
    System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(string64)));

    System.out.println("\nThird time");
    string64 = getEncryptedPassword("FenilShah");
    System.out.println(string64);
    System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(string64)));

}

 public static String getEncryptedPassword(String clearTextPassword)   {  


        try {
          MessageDigest md = MessageDigest.getInstance("SHA-256");
          md.update(clearTextPassword.getBytes());
          byte pass[] = md.digest();
          System.out.println(pass.toString());
          return Base64.encodeBase64String(StringUtils.getBytesUtf8(pass.toString()));
        } catch (NoSuchAlgorithmException e) {
          //_log.error("Failed to encrypt password.", e);
        }
        return "";
      }
 }

所以輸出是這樣的

First time
[B@5bf825cc
W0JANWJmODI1Y2M=
[B@5bf825cc

Second time
[B@1abfb235
W0JAMWFiZmIyMzU=
[B@1abfb235

Third time
[B@1f4cc34b
W0JAMWY0Y2MzNGI=
[B@1f4cc34b

這是您最直接的問題:

byte pass[] = md.digest();
System.out.println(pass.toString());

您沒有返回字符串的哈希值。 您正在返回對byte[]調用toString()的結果。 Java 中的數組不會覆蓋toString() ,因此您將獲得默認實現,它與對象的身份有關,而與字節數組中的數據無關

Object 類的 toString 方法返回一個字符串,該字符串由對象是其實例的類的名稱、at 符號字符“@”和對象哈希碼的無符號十六進制表示組成。

(數組也不會覆蓋hashCode() ,因此它也是從Object的默認實現中獲得的...)

基本上,您需要一種不同的方式將byte[]轉換為String ……當然,或者將字節數組直接存儲在數據庫中。 如果您確實想轉換為字符串,我建議您使用十六進制或 base64。 對於 base64,我建議使用iharder.net 公共域庫……或者如果您使用的是 Java 8,則可以使用java.util.Base64 (令人驚訝的是,在 XML 以外的上下文中將 base64 類引入標准庫需要很長時間,但我們走了。)

return Base64.getEncoder().encodeToString(md.digest());

不過,您的代碼還有一個問題:

md.update(clearTextPassword.getBytes());

這使用平台默認編碼將密碼轉換為字節數組。 這不是一個好主意 - 這意味着您最終可能會根據您的代碼運行的系統獲得不同的哈希值。 最好明確指定編碼:

md.update(clearTextPassword.getBytes(StandardCharsets.UTF_8));

此外,如果 SHA-256 缺失,則捕獲異常,記錄並繼續使用空白字符串幾乎肯定是錯誤的方法。 你真的想用空字符串填充你的數據庫,允許任何人使用任何密碼登錄嗎? 如果您的系統處於這種狀態,您可以做的最好的事情幾乎肯定是拒絕任何使用密碼執行任何操作的請求。 您可能希望將NoSuchAlgorithmException轉換為某種RuntimeException並重新拋出。

最后,無論如何存儲一個簡單的 SHA-256 哈希可能不是一個好主意。

  • 你可能想要一個HMAC
  • 至少應該使用隨機鹽來避免數據庫中具有相同值的相同密碼。 (否則,攻擊者可以利用該信息對他們有利。)

我遠不是安全專家,所以我不會就正確的做事方式向您提供更多建議 - 但我實際上建議嘗試找到一個由安全專家編寫的備受推崇的庫,而不是嘗試實現這一點你自己。 安全很難做對。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM