在 Unix/Linux 系統的早期演進中,密碼儲存安全 是核心課題之一。傳統 Unix 採用基於 **DES (Data Encryption Standard)** 變體的 crypt(3) 函數進行密碼單向雜湊,這套機制雖然在當時具備開創性,但隨著算力提升已暴露嚴重缺陷。本文將梳理 Unix 標準加密的歷史脈絡、技術細節、已知弱點,以及現代替代方案,為理解當代密碼學基礎設施提供歷史視角。
[a-zA-Z0-9./] 64 字元集隨機選取 2 字元,提供 12-bit 隨機性 (4096 種組合)。$salt$hash (傳統格式直接拼接),共 13 字元可列印字串 (2 字元 salt + 11 字元 hash)。| 弱點 | 影響 |
|---|---|
| 密碼長度截斷 (8 字元) | 超過 8 字元的密碼直接截斷,極大降低熵值,長密碼無意義。 |
| 僅 12-bit Salt (4096 種) | 現代 GPU 可在秒級遍歷所有 Salt 組合,大規模並行破解極其高效。 |
| DES 56-bit 金鑰空間過小 | 專用硬體 (ASIC/FPGA) 可在數天內窮舉;現代 GPU 算力更令暴力破解極其廉價。 |
| 固定 25 輪迭代不可配置 | 無法隨算力增長增加計算成本 (無「工作量因子」機制),違反現代雜湊「可調適緩慢」原則。 |
| 不支援 Unicode/多位元組字元 | 僅處理 7-bit ASCII,國際化場景嚴重受限。 |
crypt(3),/etc/passwd 可讀,極度脆弱。/etc/shadow (僅 root 可讀),緩解離線破解風險,但演算法未變。/etc/shadow 現見格式。在 Java 中處理 Unix 相容密碼驗證或遷移:
// 使用 Bouncy Castle 或 Apache Commons Codec
import org.apache.commons.codec.digest.UnixCrypt;
String hash = UnixCrypt.crypt("userPassword", "salt"); // 產生 DES crypt
boolean valid = UnixCrypt.crypt("inputPassword", storedHash).equals(storedHash);
// 依賴: org.bouncycastle:bcprov-jdk18on / com.password4j:password4j
// Password4J 範例 (現代高層 API)
import com.password4j.Password;
import com.password4j.Argon2Function;
Argon2Function argon2 = Argon2Function.getInstance(16, 3, 1, 32); // 記憶體, 迭代, 並行度, 雜湊長度
String hash = Password.hash("userPassword").addRandomSalt(16).with(argon2).getResult();
// 驗證
boolean valid = Password.check("inputPassword", storedHash).with(argon2);
@Bean
public PasswordEncoder passwordEncoder() {
// DelegatingPasswordEncoder 自動識別儲存格式前綴 ({bcrypt}, {argon2}, {SHA-256}...)
// 新編碼預設使用 BCrypt (強度 10),可改為 Argon2
String idForEncode = "bcrypt";
Map encoders = Map.of(
"bcrypt", new BCryptPasswordEncoder(10),
"argon2", new Argon2PasswordEncoder(16, 3, 1, 32), // 需 Spring Security 5.6+
"noop", NoOpPasswordEncoder.getInstance() // 僅測試用
);
return new DelegatingPasswordEncoder(idForEncode, encoders);
}
Unix 標準加密的歷史,是一部**「算力增長 vs 防禦機制演進」的軍備競賽史**。從固定 25 輪 DES 到可配置迭代的 SHA-2 Crypt,再到記憶體硬化的 Argon2,核心邏輯始終圍繞:**增加攻擊者單次嘗試成本、消除預計算優勢、適應硬體演進**。作為開發者,**請勿在任何新專案中使用傳統 crypt/MD5/SHA-1/單純 SHA-256 作為密碼雜湊**,請擁抱 Argon2id (首選) 或 bcrypt (次選),並配合 DelegatingPasswordEncoder 實現平滑遷移與多格式共存。