## 引言
密码哈希是将任意长度的输入(密码)转换为固定长度输出的过程。它是网络安全测试中的关键环节——如果你在安全扫描中发现了数据库备份文件,其中存储的就是密码的哈希值。
本文将从**开发视角**教你如何实现安全的密码哈希方案,从**测试视角**讲解如何检测和破解弱哈希。
>**法律声明**:本文仅用于安全教育和授权安全测试。未经授权访问他人系统或破解密码违反《中华人民共和国刑法》第285条和第286条。
## 第一部分:理解密码哈希
### 什么是密码哈希?
密码哈希是一种单向数学函数,它将你的原始密码转换为一段固定长度的字符串。这个过程是**不可逆的**——理论上,你无法从哈希值还原出原始密码。
```python
import hashlib
import hmac
import os
import time
import re
import math
```
例如,当你输入密码"123456"时,MD5算法会生成这样的哈希值:
```
MD5("123456") = e10adc3949ba59abbe56e057f20f883e
```
而SHA-256算法会生成更长的哈希值:
```
SHA256("123456") = 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
```
### 为什么不能用明文存储密码?
假设你开发了一个网站,用户注册时输入密码"mypassword"。如果数据库被泄露:
| 存储方式 | 泄露后果 |
|---------|---------|
| **明文存储** | 攻击者直接获得所有用户的密码 |
| **MD5哈希存储** | 攻击者需要通过其他方式破解 |
| **bcrypt/PBKDF2加盐存储** | 即使泄露,破解成本极高 |
这就是为什么**永远不要用明文存储密码**。
## 第二部分:哈希算法分析器
```python
classHashAnalyzer:
"""
密码哈希分析器
了解常见哈希算法的特性,
是进行安全测试的第一步。
"""
HASH_ALGORITHMS = {
"MD5": {
"length": 32, # MD5输出总是32个十六进制字符
"bits": 128,
"weakness": "碰撞攻击、彩虹表攻击",
"secure": False
},
"SHA1": {
"length": 40,
"bits": 160,
"weakness": "碰撞攻击(已被实际利用)",
"secure": False
},
"SHA256": {
"length": 64,
"bits": 256,
"weakness": "速度过快,易受暴力破解",
"secure": True# 适合做普通哈希,不适合密码哈希
},
"SHA512": {
"length": 128,
"bits": 512,
"weakness": "速度过快,易受暴力破解",
"secure": True
},
"SHA3_256": {
"length": 64,
"bits": 256,
"weakness": "较新,尚未发现重大弱点",
"secure": True
},
}
@staticmethod
defdetect_hash_type(hash_value: str) -> str:
"""
自动检测哈希类型
根据哈希值的长度和格式,快速判断它使用的是什么算法。
在实际渗透测试中,这一步可以帮助你快速识别目标系统使用了什么哈希算法。
"""
hash_value = hash_value.strip()
length = len(hash_value)
# 检测是否为纯十六进制
try:
int(hash_value, 16)
exceptValueError:
return"❌ 不是有效的十六进制哈希"
# 根据长度判断
if length == 32:
return"🔍 MD5 (128位)"
elif length == 40:
return"🔍 SHA-1 (160位)"
elif length == 64:
return"🔍 SHA-256 (256位)"
elif length == 128:
return"🔍 SHA-512 (512位)"
else:
returnf"❓ 未知哈希类型 (长度: {length})"
@staticmethod
defcompute_hash(text: str, algorithm: str = "sha256") -> str:
"""计算给定文本的哈希值"""
algo = getattr(hashlib, algorithm.lower())
return algo(text.encode("utf-8")).hexdigest()
@staticmethod
defcompare_hashes(hash1: str, hash2: str) -> bool:
"""
安全地比较两个哈希值(防止时序攻击)
为什么不能直接用==比较?
因为==比较是逐字符进行的,攻击者可以通过测量响应时间来
推测哈希值的每一位是否正确。
hmac.compare_digest()会在整个字符串比较完毕后才返回结果,
无论前面哪些字符匹配。
"""
return hmac.compare_digest(hash1.strip().lower(), hash2.strip().lower())
defprint_comparison_table(self):
"""打印所有算法的对比表格"""
print("=" * 70)
print("密码哈希算法对比")
print("=" * 70)
print(f"{'算法':<12}{'长度':>6}{'位数':>6}{'安全':>6}{'弱点'}")
print("-" * 70)
for name, info inself.HASH_ALGORITHMS.items():
secure_icon = "✅"if info["secure"] else"❌"
print(
f"{name:<12}{info['length']:>6}{info['bits']:>6} "
f"{secure_icon:>6}{info['weakness']}"
)
print("=" * 70)
@staticmethod
defcrack_simple_md5(
target_hash: str,
wordlist: list = None,
) -> str:
"""
使用字典碰撞法破解简单MD5
这是最常见的MD5破解方法。
对于弱密码,几乎可以瞬间破解。
Args:
target_hash: 目标MD5哈希值
wordlist: 密码字典列表
Returns:
如果找到对应明文,返回密码;否则返回None
"""
if wordlist isNone:
# 默认弱密码字典
wordlist = [
"123456", "123456789", "qwerty", "abc123",
"password", "iloveyou", "admin", "letmein",
"welcome", "monkey", "master", "dragon",
"login", "starwars", "trustno1", "sunshine",
"princess", "football", "shadow", "superman",
"michael", "test", "guest", "root", "toor",
"pass", "1234", "000000", "1111", "12345",
"1234567", "12345678", "1234567890",
"changeme", "hello", "1q2w3e4r",
]
print(f"[*] 开始破解MD5哈希: {target_hash}")
start_time = time.time()
# 预计算所有字典项的MD5,建立反向查找表
hash_to_password = {}
for pwd in wordlist:
md5_hash = hashlib.md5(pwd.encode()).hexdigest()
hash_to_password[md5_hash] = pwd
if target_hash.lower() in hash_to_password:
password = hash_to_password[target_hash.lower()]
elapsed = time.time() - start_time
print(f"[+] 破解成功!")
print(f" 密码: {password}")
print(f" 耗时: {elapsed:.4f} 秒")
return password
elapsed = time.time() - start_time
print(f"[-] 未在字典中找到匹配")
print(f" 耗时: {elapsed:.4f} 秒")
returnNone
```
### 开发视角:如何识别哈希类型
在实际开发中,你需要了解不同哈希算法的特征。下面是一个简单的哈希类型识别器:
```python
defidentify_hash_by_prefix(hash_string):
"""
通过哈希值的特征识别算法
某些哈希算法(如bcrypt)会使用特定的前缀来标识自身。
例如:
- $1$ 表示MD5-crypt
- $2a$ 或 $2b$ 表示bcrypt
- $5$ 表示SHA-256 crypt
- $6$ 表示SHA-512 crypt
"""
if hash_string.startswith("$1$"):
return"MD5-crypt"
elif hash_string.startswith(("$2a$", "$2b$", "$2y$")):
return"bcrypt"
elif hash_string.startswith("$5$"):
return"SHA-256 crypt"
elif hash_string.startswith("$6$"):
return"SHA-512 crypt"
elif re.match(r'^[a-f0-9]{32}$', hash_string):
return"MD5"
elif re.match(r'^[a-f0-9]{40}$', hash_string):
return"SHA-1"
elif re.match(r'^[a-f0-9]{64}$', hash_string):
return"SHA-256"
else:
return"未知"
```
### 测试视角:哈希碰撞实验
在渗透测试中,理解哈希碰撞至关重要。虽然理想的哈希函数应该避免碰撞,但现实中MD5等算法已被证明存在碰撞漏洞:
```python
defdemonstrate_collision_weakness():
"""演示MD5的碰撞弱点"""
# 不同内容可能产生相同的前缀哈希
# 这在实际攻击中可以用于构造恶意证书或签名
print("\n[+] MD5碰撞演示")
print("=" * 50)
str1 = "attack_at_dawn"
str2 = "defense_at_dusk"
hash1 = hashlib.md5(str1.encode()).hexdigest()
hash2 = hashlib.md5(str2.encode()).hexdigest()
print(f"输入1: '{str1}'")
print(f"MD5: {hash1}")
print()
print(f"输入2: '{str2}'")
print(f"MD5: {hash2}")
print()
print(f"相同? {hash1 == hash2}")
print()
print(f"前8位相同? {hash1[:8] == hash2[:8]}")
demonstrate_collision_weakness()
```
## 第三部分:密码强度评估
### 开发视角:构建安全的密码策略
作为开发者,你需要在用户注册时评估密码强度。以下是一个完整的密码评估器:
```python
classPasswordStrengthChecker:
"""
密码强度评估器
用于测试密码是否足够安全,是开发视角的重要工具。
它不仅仅检查密码长度,还分析密码的"熵值"——
即密码的不确定性程度。熵值越高,暴力破解成本越大。
"""
def__init__(self):
# 常见弱密码模式
self.weak_patterns = [
r"^(.+)\1+$", # 重复子串,如 "ababab"
r"^([a-zA-Z]+)\1+$", # 完全重复单词
r"^[0-9]+$", # 纯数字
r"^[a-zA-Z]+$", # 纯字母
]
defevaluate(self, password: str) -> dict:
"""
评估密码强度
Returns:
包含评分、建议和密码分析的字典
"""
score = 0
issues = []
analysis = {}
# 1. 长度评分
length = len(password)
analysis["length"] = length
if length >= 16:
score += 25
elif length >= 12:
score += 20
elif length >= 8:
score += 15
else:
score += 5
issues.append("密码长度过短(建议至少12位)")
# 2. 字符多样性评分
has_lower = bool(re.search(r"[a-z]", password))
has_upper = bool(re.search(r"[A-Z]", password))
has_digit = bool(re.search(r"\d", password))
has_special = bool(re.search(r"[!@#$%^&*(),.?\":{}|<>`~_\-\+=;'/\\|\[\]]", password))
analysis.update({
"has_lowercase": has_lower,
"has_uppercase": has_upper,
"has_digits": has_digit,
"has_special": has_special,
})
char_types_count = sum([has_lower, has_upper, has_digit, has_special])
analysis["char_types_count"] = char_types_count
score += char_types_count * 10
# 3. 检查是否包含常见弱密码
common_passwords = [
"password", "123456", "qwerty", "admin", "letmein",
"welcome", "monkey", "dragon", "master", "login",
"abc123", "test", "guest", "root",
]
if password.lower() in common_passwords:
score -= 30
issues.append("密码过于常见,极易被破解")
# 4. 检查重复字符模式
if re.match(r"^(.)\1*$", password):
score -= 20
issues.append("密码由单一字符组成")
eliflen(set(password.lower())) < length * 0.3:
score -= 10
issues.append("密码字符重复度过高")
# 5. 计算熵值(信息论角度)
charset_size = sum([
26if has_lower else0,
26if has_upper else0,
10if has_digit else0,
32if has_special else0,
])
if charset_size > 0:
entropy = length * math.log2(charset_size)
analysis["entropy_bits"] = round(entropy, 2)
score += min(int(entropy / 20), 20)
else:
analysis["entropy_bits"] = 0
# 6. 检查键盘模式
keyboard_patterns = ["qwerty", "asdfgh", "zxcvbn", "123456", "abcdef"]
if password.lower() in keyboard_patterns:
score -= 15
issues.append("密码为常见键盘排列模式")
# 最终评分(限制在0-100之间)
score = max(0, min(100, score))
analysis["score"] = score
analysis["issues"] = issues
# 评级
if score >= 80:
analysis["grade"] = "强"
elif score >= 60:
analysis["grade"] = "中等"
elif score >= 40:
analysis["grade"] = "弱"
else:
analysis["grade"] = "非常弱"
return analysis
defprint_report(self, password: str):
"""打印美观的密码强度报告"""
result = self.evaluate(password)
print(f"\n{'=' * 50}")
print(f" 密码强度评估报告")
print(f"{'=' * 50}")
print(f" 密码: {'*' * len(password)}")
print(f" 长度: {result['length']} 字符")
print(f" 评级: {result['grade']} ({result['score']}/100)")
print(f" 熵值: {result['entropy_bits']} bits")
print(f" 包含:")
print(f" 小写字母: {'✅'if result['has_lowercase'] else'❌'}")
print(f" 大写字母: {'✅'if result['has_uppercase'] else'❌'}")
print(f" 数字: {'✅'if result['has_digits'] else'❌'}")
print(f" 特殊字符: {'✅'if result['has_special'] else'❌'}")
if result["issues"]:
print(f"\n ⚠️ 问题:")
for issue in result["issues"]:
print(f" - {issue}")
else:
print(f"\n ✅ 无重大问题!")
print(f"{'=' * 50}")
```
### 测试视角:利用密码强度评估进行渗透
在渗透测试中,了解密码强度评估的逻辑可以帮助攻击者:
1.**针对性选择字典**:如果系统要求大小写+数字+特殊字符,攻击者会优先使用包含这些模式的字典。
2.**规则字典生成**:基于已知规则(如"首字母大写+末尾加1"),生成更高效的字典。
3.**绕过前端验证**:很多网站在前端进行密码强度检查,但后端没有验证——攻击者可以直接提交绕过。
## 第四部分:安全哈希实现
### 开发视角:正确的密码存储方式
对于密码存储,不能使用普通的MD5或SHA256。必须使用:
1.**盐值(Salt)**:每个密码都有一个唯一随机值附加
2.**密钥拉伸(Key Stretching)**:增加计算成本,减缓暴力破解
3.**专用哈希函数**:如bcrypt、scrypt、Argon2
以下是使用Python标准库实现的PBKDF2-HMAC-SHA256方案:
```python
classSecurePasswordHasher:
"""
安全的密码哈希实现
使用PBKDF2-HMAC-SHA256(Python内置支持)
为什么选择PBKDF2?
- 它是NIST推荐的标准算法
- 可调节迭代次数,适应硬件发展
- Python标准库原生支持,无需安装第三方包
生产环境中更推荐使用bcrypt或Argon2,
因为它们专门针对密码哈希优化。
"""
@staticmethod
defhash_password_secure(password: str, salt: bytes = None) -> dict:
"""
使用PBKDF2-HMAC-SHA256进行安全的密码哈希
相比MD5/SHA256,这个方案的优势:
1. 使用盐值(salt)防止彩虹表攻击
2. 使用多次迭代增加暴力破解成本
3. 输出标准化,便于存储
"""
if salt isNone:
salt = os.urandom(32) # 32字节随机盐
# PBKDF2-HMAC-SHA256,210000次迭代
# 210000是根据NIST 2023建议推荐的最低值
iterations = 210000
dk = hashlib.pbkdf2_hmac(
"sha256",
password.encode("utf-8"),
salt,
iterations
)
return {
"hash": dk.hex(),
"salt": salt.hex(),
"iterations": iterations,
"algorithm": "pbkdf2_sha256"
}
@staticmethod
defverify_password(password: str, stored: dict) -> bool:
"""
验证密码是否正确
使用hmac.compare_digest()防止时序攻击
"""
salt = bytes.fromhex(stored["salt"])
iterations = stored["iterations"]
expected_hash = bytes.fromhex(stored["hash"])
computed_hash = hashlib.pbkdf2_hmac(
"sha256",
password.encode("utf-8"),
salt,
iterations
)
return hmac.compare_digest(computed_hash, expected_hash)
@staticmethod
defbenchmark():
"""基准测试:比较不同算法的性能差异"""
password = "MySecureP@ssw0rd123!"
algorithms = ["md5", "sha1", "sha256", "sha512"]
results = {}
print(f"\n{'=' * 50}")
print(f" 密码哈希性能基准测试")
print(f" 测试密码: {'*' * len(password)}")
print(f"{'=' * 50}")
for algo in algorithms:
start = time.time()
for _ inrange(10000):
hashlib.new(algo, password.encode()).hexdigest()
elapsed = time.time() - start
results[algo] = elapsed
print(f" {algo.upper():>8}: {elapsed:.3f}s / 10000次")
print(f"\n 结论: 算法越快,越容易暴力破解")
print(f" 密码存储应使用慢速哈希(bcrypt/argon2/pbkdf2)")
```
### 测试视角:如何绕过不安全的哈希
在渗透测试中,你可能会遇到以下几种情况:
| 场景 | 破解难度 | 推荐方法 |
|------|---------|---------|
| MD5无盐 | 非常容易 | 字典攻击、在线彩虹表 |
| MD5加盐 | 中等 | 字典攻击(需先获取盐值) |
| SHA256无盐 | 容易 | 字典攻击、彩虹表 |
| bcrypt加盐 | 困难 | GPU暴力破解、云算力 |
| Argon2加盐 | 非常困难 | 需要大规模分布式攻击 |
#### 彩虹表攻击原理
彩虹表是一种空间-时间权衡的攻击方法。它的核心思想是:
1. 预先计算大量常见密码的哈希值
2. 将结果存储在表中
3. 通过查表快速获取密码
```python
defdemonstrate_rainbow_table_attack():
"""演示彩虹表攻击的基本原理"""
print("\n[+] 彩虹表攻击演示")
print("=" * 50)
# 模拟彩虹表
rainbow_table = {}
common_passwords = ["password", "123456", "admin", "qwerty", "letmein"]
for pwd in common_passwords:
md5_hash = hashlib.md5(pwd.encode()).hexdigest()
rainbow_table[md5_hash] = pwd
# 目标哈希
target_hash = "5f4dcc3b5aa765d61d8327deb882cf99"# "password"的MD5
if target_hash in rainbow_table:
print(f"[!] 找到匹配!")
print(f" 哈希: {target_hash}")
print(f" 密码: {rainbow_table[target_hash]}")
else:
print("[-] 未在彩虹表中找到匹配")
demonstrate_rainbow_table_attack()
```
## 第五部分:综合实战
### 开发视角:构建完整的密码安全管理模块
```python
classPasswordManager:
"""
完整的密码安全管理模块
集成哈希、验证、评估等功能,
为开发提供参考实现。
"""
def__init__(self):
self.analyzer = HashAnalyzer()
self.checker = PasswordStrengthChecker()
self.hasher = SecurePasswordHasher()
defregister_user(self, username: str, password: str) -> dict:
"""新用户注册流程"""
# 1. 检查密码强度
strength = self.checker.evaluate(password)
if strength["score"] < 60:
return {
"success": False,
"error": "密码强度不足",
"issues": strength["issues"]
}
# 2. 生成安全哈希
hash_result = self.hasher.hash_password_secure(password)
# 3. 模拟存储
print(f" 用户 '{username}' 注册成功")
print(f" 哈希算法: {hash_result['algorithm']}")
print(f" 盐值: {hash_result['salt'][:16]}...")
print(f" 迭代次数: {hash_result['iterations']}")
return {
"success": True,
"username": username,
"hash_info": hash_result
}
deflogin_user(self, username: str, password: str, stored_hash_info: dict) -> bool:
"""用户登录验证"""
is_valid = self.hasher.verify_password(password, stored_hash_info)
if is_valid:
print(f" 用户 '{username}' 登录成功")
else:
print(f" 用户 '{username}' 登录失败: 密码错误")
return is_valid
```
### 测试视角:密码哈希安全审计工具
```python
classHashSecurityAuditor:
"""
密码哈希安全审计工具
用于在渗透测试中快速识别系统中的哈希漏洞。
"""
def__init__(self):
self.analyzer = HashAnalyzer()
defaudit_database_dump(self, hashes: list) -> dict:
"""
审计数据库转储文件中的哈希值
返回:
{
"total_hashes": 100,
"md5_count": 45,
"sha1_count": 10,
"sha256_count": 30,
"bcrypt_count": 15,
"vulnerabilities": [...],
"risk_level": "HIGH"
}
"""
stats = {"md5": 0, "sha1": 0, "sha256": 0, "bcrypt": 0, "unknown": 0}
vulnerabilities = []
for h in hashes:
detection = self.analyzer.detect_hash_type(h)
if"MD5"in detection:
stats["md5"] += 1
vulnerabilities.append({
"hash": h[:16] + "...",
"issue": "MD5已被证明不安全,易受碰撞攻击",
"severity": "HIGH"
})
elif"SHA-1"in detection:
stats["sha1"] += 1
vulnerabilities.append({
"hash": h[:16] + "...",
"issue": "SHA-1已存在实用碰撞攻击",
"severity": "HIGH"
})
elif"SHA-256"in detection:
stats["sha256"] += 1
vulnerabilities.append({
"hash": h[:16] + "...",
"issue": "SHA-256速度快,易受GPU暴力破解",
"severity": "MEDIUM"
})
elif"bcrypt"in detection.lower() or h.startswith(("$2a$", "$2b$", "$2y$")):
stats["bcrypt"] += 1
else:
stats["unknown"] += 1
# 评估风险等级
risk_score = (
stats["md5"] * 3 +
stats["sha1"] * 3 +
stats["sha256"] * 1 +
stats["unknown"] * 2
)
if risk_score > 50:
risk_level = "CRITICAL"
elif risk_score > 20:
risk_level = "HIGH"
elif risk_score > 10:
risk_level = "MEDIUM"
else:
risk_level = "LOW"
return {
"total_hashes": len(hashes),
"algorithm_stats": stats,
"vulnerabilities": vulnerabilities[:10], # 最多返回10条
"risk_level": risk_level,
"risk_score": risk_score
}
# 示例使用
defrun_audit_demo():
"""演示哈希安全审计"""
print("\n" + "=" * 50)
print(" 哈希安全审计报告")
print("=" * 50)
auditor = HashSecurityAuditor()
# 模拟从数据库中导出的哈希值
sample_hashes = [
"e10adc3949ba59abbe56e057f20f883e", # MD5: 123456
"5f4dcc3b5aa765d61d8327deb882cf99", # MD5: password
"5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", # SHA1: password
"ef92b778bafe771e89245b89ecbc08a44a4e166c", # MD5: 123456789
"5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8", # SHA256
"$2b$12$LJ3m4ys9L8Kq3V7qZ8x7Wu", # bcrypt
]
report = auditor.audit_database_dump(sample_hashes)
print(f" 分析哈希总数: {report['total_hashes']}")
print(f" 风险等级: {report['risk_level']}")
print(f"\n 算法统计:")
for algo, count in report['algorithm_stats'].items():
if count > 0:
print(f" {algo}: {count}")
if report['vulnerabilities']:
print(f"\n 发现的漏洞:")
for v in report['vulnerabilities']:
print(f" [{v['severity']}] {v['issue']}")
run_audit_demo()
```
## 第六部分:攻防双方对比
### 开发方:如何正确实现密码存储
以下是生产环境中推荐的密码存储方案:
| 要素 | 推荐值 | 说明 |
|------|--------|------|
| 算法 | Argon2id / bcrypt / PBKDF2 | 优先Argon2 |
| 盐值 | 16字节随机 | 每个用户独立 |
| 迭代次数 | bcrypt: 12+, Argon2: 3次 | 根据硬件调整 |
| 密码长度限制 | 至少64字符 | 防止截断攻击 |
| 账号锁定 | 10次失败后锁定 | 防止在线暴力破解 |
| 日志记录 | 记录登录时间/IP | 但不记录密码 |
### 测试方:如何有效破解弱哈希
以下是渗透测试中常用的密码破解技巧:
| 方法 | 适用场景 | 成功率 |
|------|---------|--------|
| 字典攻击 | MD5/SHA1无盐 | 90%+(常见密码) |
| 彩虹表 | 标准MD5/SHA1 | 80%+(在线工具) |
| 暴力破解 | 短密码(<6位) | 接近100% |
| 规则攻击 | bcrypt加盐 | 10-30%(弱密码) |
| GPU加速 | 大规模哈希 | 速度提升10-50倍 |
| 撞库 | 用户重用密码 | 取决于密码复用率 |
### 实战演练:破解一个真实案例
假设你在安全测试中发现一个系统的用户密码使用MD5存储,且没有加盐:
```python
defcrack_real_world_case():
"""
破解一个真实场景:MD5无盐存储的密码
这种场景在早期Web应用中非常普遍,
也是渗透测试中最容易获取成果的方向。
"""
print("\n" + "=" * 50)
print(" 实战:MD5无盐密码破解")
print("=" * 50)
analyzer = HashAnalyzer()
# 1. 检测哈希类型
sample_hash = "e10adc3949ba59abbe56e057f20f883e"
detected = analyzer.detect_hash_type(sample_hash)
print(f" 检测到哈希类型: {detected}")
# 2. 使用弱密码字典破解
result = analyzer.crack_simple_md5(sample_hash)
if result:
print(f" 成功破解!密码为: {result}")
else:
print(f" 未能破解,建议扩大字典范围")
crack_real_world_case()
```
## 第七部分:总结与最佳实践
### 开发视角总结
1.**永远不要使用MD5/SHA1存储密码** —— 它们太快且存在碰撞漏洞
2.**使用PBKDF2、bcrypt或Argon2** —— 这些算法专门为密码哈希设计
3.**每个密码必须有独立的随机盐值** —— 防止彩虹表攻击
4.**定期更新迭代参数** —— 随着硬件发展,需要增加破解成本
5.**实施多层防御** —— 不仅依赖哈希,还要加账号锁定、速率限制
### 测试视角总结
1.**先识别哈希类型** —— 通过长度和前缀快速判断算法
2.**优先尝试字典攻击** —— 大多数用户使用的密码都在常见密码列表中
3.**利用在线工具** —— 如Hashes.com、OnlineMD5Cracker等
4.**尝试规则生成** —— 基于"用户习惯"生成变种密码
5.**关注实现漏洞** —— 开发者可能犯了"伪加盐"的错误(如用用户名当盐值)
### 核心要点
密码安全是一场攻防之间的持续对抗。开发者需要不断升级防御,攻击者需要不断创新突破。理解双方的思路和方法,是成为一名优秀安全从业者的基础。
记住:**安全不是产品功能,而是一种态度。**
---
## 练习题
### 开发视角练习
1. 实现一个完整的用户注册/登录系统,包含密码强度检查和PBKDF2哈希
2. 为你的系统设计一个密码重置功能,确保令牌一次性且有效期合理
3. 添加多因素认证(MFA),至少支持TOTP(时间一次性密码)
4. 实现密码修改时的旧密码验证和新密码强度检查
### 测试视角练习
1. 收集100个MD5哈希值,编写脚本统计各种算法的分布比例
2. 使用hashcat或John the Ripper破解一个弱MD5哈希数据库
3. 分析一个真实泄露数据集(如LinkedIn 2012泄露),统计密码强度分布
4. 比较MD5、SHA1、bcrypt三种算法在不同密码长度下的破解时间
### 进阶挑战
1. 实现一个彩虹表生成器和查询器,理解空间-时间权衡的原理
2. 对比分析bcrypt、scrypt、Argon2三种算法的安全性和性能差异
3. 编写一个自动化密码审计工具,扫描Web应用中的所有哈希实现
4. 实现一个侧信道攻击模拟程序,展示时序攻击如何泄露哈希比较结果