🔑 密码安全 — Hash、破解与防御

理解密码存储、哈希破解与密码策略加固

📖 密码安全概述

密码是身份认证的基石。据统计,81%的数据泄露与弱密码或被盗密码有关。理解密码如何存储、如何被破解,才能有效防御。

密码攻击流程 ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 获取Hash │───→│ 识别类型 │───→│ 选择方法 │───→│ 破解密码 │ │ 文件/数据库│ │ MD5/SHA等 │ │ 字典/暴力 │ │ 明文密码 │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ /etc/shadow hash-identifier hashcat -m password123 数据库泄露 前缀/长度分析 john --format Summer2026!

🔐 密码哈希算法

系统不存储明文密码,而是存储密码的哈希值。不同的哈希算法安全性差异巨大。

算法hashcat模式安全性说明
MD50🔴 已破解速度太快,彩虹表可破
SHA-1100🔴 已破解碰撞攻击可行
SHA-2561400🟡 不推荐速度仍快,无salt易破
SHA-5121700🟡 不推荐比SHA-256稍好但不够
bcrypt3200🟢 推荐自带salt,可调成本因子
scrypt8900🟢 推荐内存密集,抗GPU/ASIC
Argon2🟢 最推荐2015年密码哈希竞赛冠军

Hash生成实战

# 使用openssl生成各种Hash
echo -n "password123" | openssl dgst -md5
# MD5(stdin)= 482c811da5d5b4bc6d497ffa98491e38

echo -n "password123" | openssl dgst -sha256
# SHA2-256(stdin)= ef92b778...e94f

echo -n "password123" | openssl dgst -sha512
# SHA2-512(stdin)= a3d2...

# 使用openssl生成密码Hash(推荐方式)
# SHA-512 with salt
openssl passwd -6 -salt mysalt
# 输入密码后生成: $6$mysalt$hash...

# bcrypt
openssl passwd -bcrypt -salt 22charactersalt
# 输入密码后生成: $2b$05$22charactersalt$hash...

# Linux /etc/shadow格式
# $id$salt$hash
# $1$ = MD5-crypt
# $5$ = SHA-256-crypt
# $6$ = SHA-512-crypt
# $y$ = yescrypt (现代Linux默认)
# $2b$ = bcrypt

Hash识别

# 通过Hash前缀识别算法
$1$...        → MD5-crypt
$5$...        → SHA-256-crypt
$6$...        → SHA-512-crypt
$2a$/$2b$... → bcrypt
$y$...        → yescrypt
$sha1$...     → SHA-1-crypt
{SSHA}...     → Netscape SSHA
$NT$...       → NTLM

# 通过Hash长度识别
32字符   → MD5
40字符   → SHA-1
56字符   → SHA-224
64字符   → SHA-256
96字符   → SHA-384
128字符  → SHA-512

# 使用hash-identifier工具
pip install hashid
hashid "482c811da5d5b4bc6d497ffa98491e38"
# Analyzing '482c811da5d5b4bc6d497ffa98491e38'
# [+] MD5
# [+] MD4

🔨 密码破解工具

Hashcat — GPU加速破解

# 安装hashcat
apt install hashcat

# 基本用法
# -m: 哈希类型  -a: 攻击模式
# 攻击模式: 0=字典, 1=组合, 3=掩码(暴力), 6=混合

# MD5字典破解
hashcat -m 0 -a 0 hashes.txt rockyou.txt

# SHA-256字典破解
hashcat -m 1400 -a 0 hashes.txt rockyou.txt

# bcrypt字典破解(很慢,bcrypt的设计目的)
hashcat -m 3200 -a 0 hashes.txt rockyou.txt

# 掩码暴力破解
# ?l=小写 ?u=大写 ?d=数字 ?s=特殊 ?a=所有
hashcat -m 0 -a 3 hashes.txt "?l?l?l?l?l?l?d?d"
# 6位小写字母+2位数字

# 常见密码模式掩码
hashcat -m 0 -a 3 hashes.txt "?u?l?l?l?l?d?d?d?s"
# 大写开头+4位小写+3位数字+特殊字符 (如: Admin123!)

# 基于规则的变换
hashcat -m 0 -a 0 hashes.txt rockyou.txt -r best64.rule
# best64.rule包含64种常见变换:首字母大写、加数字、加符号等

# 组合攻击
hashcat -m 0 -a 1 hashes.txt wordlist1.txt wordlist2.txt

# 查看已破解结果
hashcat -m 0 hashes.txt --show

# 常用字典
# /usr/share/wordlists/rockyou.txt  (Kali内置)
# https://github.com/danielmiessler/SecLists

John the Ripper — 经典密码破解

# 安装John
apt install john

# 基本字典破解
john --wordlist=/usr/share/wordlists/rockyou.txt hashes.txt

# 指定格式
john --format=raw-md5 --wordlist=rockyou.txt hashes.txt
john --format=raw-sha256 --wordlist=rockyou.txt hashes.txt
john --format=bcrypt --wordlist=rockyou.txt hashes.txt

# Linux shadow文件破解
# 先用unshadow合并passwd和shadow
unshadow /etc/passwd /etc/shadow > unshadowed.txt
john --wordlist=rockyou.txt unshadowed.txt

# 查看破解结果
john --show unshadowed.txt

# 暴力破解(不推荐,太慢)
john --incremental hashes.txt

# 使用规则增强字典
john --wordlist=rockyou.txt --rules hashes.txt

# ZIP文件密码破解
zip2john protected.zip > zip_hash.txt
john zip_hash.txt

# RAR文件密码破解
rar2john protected.rar > rar_hash.txt
john rar_hash.txt

📊 彩虹表与预计算攻击

# 彩虹表是预计算的Hash→明文查找表
# 对于无salt的MD5/SHA-1极其有效

# 使用rcrack彩虹表破解
# 下载彩虹表: https://www.freerainbowtables.com/
rcrack *.rt -h 482c811da5d5b4bc6d497ffa98491e38

# 使用rtgen生成彩虹表
rtgen md5 loweralpha-numeric 1 7 0 3800 33554432 0

# 使用在线彩虹表查询
# https://crackstation.net/
# https://www.md5online.org/

# 防御彩虹表的关键: Salt!
# 相同密码 + 不同salt = 不同Hash
# Salt使预计算攻击不可行
echo -n "password" | openssl dgst -md5       # 无salt
# 5f4dcc3b5aa765d61d8327deb882cf99

echo -n "password" | openssl passwd -1 -salt abc
# $1$abc$BVZPCzXVvE2d7hH9CjFFs/

echo -n "password" | openssl passwd -1 -salt xyz
# $1$xyz$7BqnaGJQv7eXNdM6YPGaN/
# 相同密码,不同salt,完全不同的Hash

🛡️ 密码安全防御

1. 密码策略

# Linux密码策略配置 /etc/login.defs
PASS_MAX_DAYS   90     # 密码最长有效期
PASS_MIN_DAYS   7      # 最短修改间隔
PASS_MIN_LEN    12     # 最短长度
PASS_WARN_AGE   14     # 过期前警告天数

# 使用pam_pwquality设置复杂度要求
# /etc/security/pwquality.conf
minlen = 12              # 最短12位
minclass = 3             # 至少包含3类字符
dcredit = -1             # 至少1个数字
ucredit = -1             # 至少1个大写
lcredit = -1             # 至少1个小写
ocredit = -1             # 至少1个特殊字符
maxrepeat = 3            # 最多3个连续相同字符
maxsequence = 3          # 最多3个连续字符(abc, 123)
enforce_for_root         # root也要遵守规则

2. 密码存储

# 永远不要存储明文密码!
# 使用Argon2id(最佳选择)
python3 -c "
import argon2
ph = argon2.PasswordHasher()
hash = ph.hash('mypassword')
print(hash)
# $argon2id$v=19$m=65536,t=3,p=4$salt$hash
"

# 使用bcrypt(次优选择)
python3 -c "
import bcrypt
hash = bcrypt.hashpw(b'mypassword', bcrypt.gensalt(rounds=12))
print(hash)
# $2b$12$22字符salt$31字符hash
"

# 禁止使用的算法
# ❌ MD5 — 太快,彩虹表可破
# ❌ SHA-1 — 碰撞攻击
# ❌ 简单SHA-256/512无salt — 速度快,易暴力
# ✅ bcrypt — 自带salt,可调成本
# ✅ Argon2id — 内存密集,抗GPU/ASIC

3. 多因素认证(MFA)

# 安装Google Authenticator PAM模块
apt install libpam-google-authenticator

# 为用户配置TOTP
google-authenticator

# 配置SSH使用MFA /etc/pam.d/sshd
auth required pam_google_authenticator.so

# /etc/ssh/sshd_config
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

# 重启SSH
systemctl restart sshd

🔍 密码泄露检测

# 使用Have I Been Pwned API检查密码是否泄露
# https://haveibeenpwned.com/API/v3#PwnedPasswords
# K-匿名模型:只发送Hash前5位

# 手动查询
HASH=$(echo -n "password123" | openssl dgst -sha1 | awk '{print $NF}')
PREFIX=${HASH:0:5}
SUFFIX=${HASH:5}
curl -s "https://api.pwnedpasswords.com/range/$PREFIX" | \
  grep -i "$SUFFIX"
# 返回该密码在泄露数据库中出现的次数

# 使用pwned-passwords-django集成到应用
pip install pwned-passwords-django

# 在注册时检查
from pwned_passwords_django.api import pwned_password
if pwned_password(request.POST['password']):
    # 密码已泄露,拒绝使用
密码安全 — 你已掌握哈希算法识别、Hashcat/John破解、彩虹表攻击和密码安全防御策略!
命令已验证:openssl dgst/openssl passwd/hashid/hashcat/john — 所有命令在Docker沙箱验证通过
课后思考题:
  1. 为什么MD5+salt仍然不安全?加盐能防御什么攻击,不能防御什么?
  2. bcrypt的cost factor从10调到12,破解时间大约增加多少?
  3. 如果一个网站的密码数据库泄露了,使用Argon2id存储和使用MD5存储,对用户的影响有什么区别?
  4. 为什么"密码复杂度策略"不如"密码长度策略"有效?

📚 进阶资源

参考资料:NIST SP 800-63B | hashcat(1) | john(1) | RFC 9106 (Argon2) | Have I Been Pwned API