繁體中文(香港)
  • auth
  • password
  • security
  • hashing
  • bcrypt
  • argon2
  • sha1
  • sha2
  • login
  • sign-in

密碼哈希的演變

你可能聽過選擇密碼哈希算法的建議,但你有冇諗過點解佢哋被推薦?喺本文中,我哋將探討密碼哈希算法嘅演變同背後嘅原因。

Gao
Gao
Founder

Stop wasting weeks on user auth
Launch secure apps faster with Logto. Integrate user auth in minutes, and focus on your core product.
Get started
Product screenshot

介紹

顧名思義,密碼哈希係計算密碼嘅哈希值嘅過程。哈希值通常存儲喺數據庫中,而喺登錄過程中,會計算用戶輸入嘅密碼嘅哈希值,並將其與存儲喺數據庫中的哈希值進行比較。如果匹配,用戶將被驗證。

喺我哋深入探討密碼哈希算法嘅演變之前,重要嘅係了解為何呢個係必需嘅。

明文密碼:主要安全風險

想像一下,你係一個網站嘅用戶,喺嗰度註冊咗一個帳戶。有一日,網站被黑客入侵,數據庫洩露咗。如果網站將密碼以明文形式存儲,黑客可以直接訪問你嘅密碼。由於許多人喺多個網站上重用密碼,黑客可以使用呢個密碼獲得你其他帳戶嘅未經授權訪問。如果你喺電郵帳戶上使用相同或類似嘅密碼,情況會更糟,因為黑客可以重置你嘅密碼,並控制你所有相關嘅帳戶。

即使冇數據洩露,喺大團隊中,任何擁有數據庫訪問權限嘅人都可以看到密碼。與其他信息相比,密碼極其敏感,你絕對唔希望任何人可以訪問佢哋。

無哈希存儲密碼係一個初級錯誤。不幸嘅係,如果你搜索“密碼洩漏明文”,你會發現大企業例如 FacebookDailyQuizGoDaddy 都曾經經歷明文密碼洩漏事件。可以話,仲有好多其他公司做咗相同嘅錯誤。

編碼 v.s. 加密 v.s. 哈希

呢三個術語經常會混淆,但佢哋係唔同嘅概念。

編碼

編碼係密碼存儲中首先應排除嘅。例如, Base64 係一種將二進制數據轉換成字符串嘅編碼算法:

知道編碼算法可以讓任何人解碼編碼嘅字符串,進而檢索原始數據:

對黑客來講,大多數編碼算法相當於明文。

加密

喺哈希普及之前,加密被用嚟存儲密碼,例如 AES。加密涉及使用一個密鑰(或成對密鑰)加密同解密數據。

加密嘅問題喺於“解密”這個詞。加密係可逆嘅,意味住如果黑客獲得密鑰,佢哋可以解密密碼,進而得到明文密碼。

哈希

哈希、編碼同加密嘅主要區別喺於哈希係 不可逆的。一旦密碼被哈希,就無法解密返佢原來嘅樣子。

作為網站擁有者,只要用戶能用正確嘅密碼登錄,你其實唔需要知道密碼本身。註冊過程可以簡化為以下幾步:

  1. 用戶輸入密碼。
  2. 服務利用哈希算法計算密碼嘅哈希值。
  3. 服務將哈希值存儲喺數據庫中。

當用戶登錄時,過程如下:

  1. 用戶輸入密碼。
  2. 服務利用相同嘅哈希算法計算密碼嘅哈希值。
  3. 服務將哈希值與數據庫中存儲嘅哈希值進行比較。
  4. 如果哈希值匹配,用戶將被驗證。

兩個過程都避免咗將密碼以明文存儲,由於哈希係不可逆嘅,即使數據庫被入侵,黑客所能獲得嘅只是看似隨機字符串嘅哈希值。

哈希算法入門包

哈希似乎係密碼存儲嘅完美解決方案,但事情冇咁簡單。為咗了解原因,我哋來探討一下密碼哈希算法嘅演變。

MD5

喺 1992 年,Ron Rivest 設計咗 MD5算法,一種信息摘要算法,可以從任何數據計算出一個 128-bit 的哈希值。MD5 廣泛應用喺各個領域,包括密碼哈希。例如,“123456”嘅 MD5 哈希值係:

如之前提及,哈希值看似隨機字符串且不可逆。此外,MD5 快速而易於實施,令其成為最受歡迎嘅密碼哈希算法。

然而,MD5 嘅優點喺密碼哈希中變成咗其弱點。由於其速度,MD5 易受暴力破解攻擊。如果黑客擁有一份常用密碼及你嘅個人信息清單,佢哋可以計算出每個組合嘅 MD5 哈希值,並與數據庫中的哈希值進行比較。例如,佢哋可能會將你嘅生日同你嘅名或你嘅寵物名結合。

喺現今,計算機比以前強大得多,較易暴力破解 MD5 密碼哈希。

SHA 家族

咁,點解唔使用另一個生成更長哈希值嘅算法? SHA 家族 似乎係個好選擇。SHA-1 係一種生成 160-bit 哈希值嘅哈希算法,SHA-2 則係生成 224-bit、256-bit、384-bit 同 512-bit 長度哈希值的哈希算法家族。睇睇“123456”嘅 SHA-256 哈希值:

SHA-256 哈希值相比 MD5 更長,亦係不可逆嘅。但仲有另一個問題:如果你已經知道哈希值,例如上面的嗰個,當你喺數據庫中見到相同嘅哈希值,你知道密碼係“123456”。黑客可以創建一個常用密碼同對應哈希值嘅列表,並同數據庫中嘅哈希值進行比較。呢個列表被稱為彩虹表。

Salt

為咗減少彩虹表攻擊,salt 嘅概念被引入。salt 係一個隨機字符串,喺哈希前加到密碼上。例如,如果 salt 係“salt”,而你想用 SHA-256 哈希加上 salt 嘅密碼“123456”,唔係簡單地這樣:

而係這樣:

你可以見到,結果與冇用 salt 嘅哈希結果完全不同。通常,喺註冊時,每個用戶都被分配一個隨機的 salt,並將其與哈希值一同存儲在數據庫中。喺登錄過程中,使用 salt 計算輸入密碼嘅哈希值,然後將其與存儲嘅哈希值進行比較。

迭代

儘管加入有 salt,哈希值仍會隨著硬件嘅提升而容易受到暴力破解攻擊。為咗更難破解,可以引入迭代(即運行哈希算法多次)。例如,唔再使用:

而係使用:

增加迭代次數使暴力破解更困難。不過,呢亦會影響登錄過程,使其變慢。因此,需要在安全與性能之間取得平衡。

中場休息

讓我哋休息一下,总結良好密碼哈希算法嘅特征:

  • 不可逆(原像抵抗性)
  • 疑難暴力破解
  • 抵抗彩虹表攻擊

你可能注意到,salt 同迭代係必需嘅,以滿足所有呢啲要求。問題係 MD5 同 SHA 家族都唔係專門為密碼哈希而設計嘅;佢哋廣泛用於完整性檢查(即“信息摘要”)。因此,每個網站可能都有自己實現嘅 salt 同迭代,使標準化同遷移變得困難。

密碼哈希算法

為咗解決這個問題,幾種專門為密碼哈希設計嘅哈希算法被引入。讓我哋看看其中一些。

bcrypt

bcrypt 係由 Niels Provos 同 David Mazières 設計嘅密碼哈希算法,在許多編程語言中都被廣泛應用。以下係 bcrypt 哈希值嘅例子:

雖然它看似又是一個隨機字符串,但它包含其他信息。讓我哋來分解一下:

  • 第一部分 $2y 表示使用嘅算法係 2y
  • 第二部分 $12 表示迭代次數係 12。即運行該哈希算法 212=4096 次(迭代次數)。
  • 第三部分 wNt7lt/xf8wRJgPU7kK2ju 係 salt。
  • 最後一部分 GrirhHK4gdb0NiCRdsSoAxqQoNbiluu 係哈希值。

bcrypt 有一些限制:

  • 密碼嘅最大長度係 72 字節。
  • salt 限制為 16 字節。
  • 哈希值限制為 184 位。

Argon2

由於對現有密碼哈希算法嘅討論同限制,一場 密碼哈希競賽 喺 2015 年舉行。跳過細節,讓我哋關注贏家:Argon2。

Argon2 係由 Alex Biryukov、Daniel Dinu 同 Dmitry Khovratovich 設計嘅密碼哈希算法。它引入咗幾個新概念:

  • 記憶體難度:算法被設計成難於並行化,使得用 GPU 暴力破解變得困難。
  • 時間難度:算法被設計成難以優化,使得用 ASIC(特定用途集成電路)暴力破解困難。
  • 側信道抵抗:算法被設計成抵抗側信道攻擊,例如時序攻擊。

Argon2 有兩個主要版本,Argon2i 同 Argon2d。Argon2i 係最安全嘅對抗側信道攻擊,而 Argon2d 提供最高抵抗能力對抗 GPU 破解攻擊。

-- Argon2

以下係 Argon2 哈希值嘅例子:

讓我哋來分解一下:

  • 第一部分 $argon2i 表示使用嘅算法係 argon2i
  • 第二部分 $v=19 表示版本係 19
  • 第三部分 $m=16,t=2,p=1 表示記憶體成本、時間成本和並行度,分別係 1621
  • 第四部分 $YTZ5ZnpXRWN5SlpjMHBDRQ 係 salt。
  • 最後一部分 $12oUmJ6xV5bIadzZHkuLTg 係哈希值。

喺 Argon2 中,密碼嘅最大長度係 232-1 字節,salt 嘅限制係 232-1 字節,哈希值嘅限制亦係 232-1 字節。這應該能滿足大多數場景。

Argon2 現在喺許多編程語言中都可用,例如 node-argon2 用於 Node.js 和 argon2-cffi 用於 Python。

結論

多年來,密碼哈希算法經歷咗重大演變。我要感謝安全社區幾十年來為讓互聯網成為更安全的地方所付出嘅努力。多虧佢哋嘅貢獻,開發者可以更專注於建立更好嘅服務,毋需擔心密碼哈希嘅安全。雖然在一個系統中實現 100% 的安全可能係唔可能嘅,但我哋可以採用多種策略以將相關風險降到最低。

如果你唔想花費時間實施認證同授權,唔妨免費試下 Logto。我哋提供安全(我哋使用 Argon2!)、可靠且可擴展嘅方案,使你能夠專注於建立你嘅產品。