0%

DVWA - Cryptography (密码学) 攻防练习详解

目录


漏洞简介

什么是密码学漏洞(Cryptography Vulnerabilities)?

密码学漏洞是指在加密、哈希、签名等密码学操作中使用不安全的算法、错误的实现或不当的密钥管理,导致数据泄露或被篡改。

密码学的核心概念:

1. 对称加密(Symmetric Encryption)

使用相同密钥进行加密和解密:

1
2
3
4
明文 + 密钥 → 加密 → 密文
密文 + 密钥 → 解密 → 明文

算法:AES, DES, 3DES, Blowfish

2. 非对称加密(Asymmetric Encryption)

使用公钥加密,私钥解密:

1
2
3
4
明文 + 公钥 → 加密 → 密文
密文 + 私钥 → 解密 → 明文

算法:RSA, ECC, DSA

3. 哈希函数(Hash Functions)

单向函数,生成固定长度的摘要:

1
2
3
4
任意数据 → 哈希 → 固定长度摘要

算法:SHA-256, SHA-3, bcrypt
不安全:MD5, SHA-1

4. 消息认证码(MAC)

验证消息完整性和真实性:

1
2
3
消息 + 密钥 → HMAC → 认证码

算法:HMAC-SHA256

常见密码学漏洞:

漏洞类型 描述 示例
弱算法 使用已被攻破的算法 MD5, DES, RC4
短密钥 密钥长度不足 56位DES密钥
硬编码密钥 密钥写死在代码中 key=”12345678”
ECB模式 不安全的分组模式 AES-ECB
无IV 不使用初始化向量 重复的密文
弱随机数 可预测的随机数 rand(), mt_rand()
重放攻击 缺少时间戳/nonce 重复使用token

危害:

  • 密码被破解
  • 数据被解密
  • 消息被篡改
  • 身份被伪造
  • 签名被伪造

DVWA场景:
一个加密消息传输系统,使用不同强度的加密方法。


Low 难度

攻击目标

使用已被攻破的MD5算法,可以轻易破解。

后端代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php

// ★★★ Low难度:使用不安全的MD5哈希 ★★★

// 获取用户密码
$password = $_POST['password'] ?? '';

// ★★★ 危险操作:使用MD5哈希密码 ★★★
// md5() - MD5哈希函数(已被攻破,不安全!)
// 返回:32位十六进制字符串
//
// 问题:
// 1. MD5已被攻破,存在碰撞攻击
// 2. MD5速度快,易于暴力破解
// 3. 没有使用盐(salt)
// 4. 彩虹表攻击可以快速破解
//
// MD5的碰撞:
// 两个不同的输入可以产生相同的MD5哈希
$hashed = md5($password);

// ★★★ 存储到数据库 ★★★
// 实际应用中会存储这个哈希
// 但攻击者获取数据库后可以轻易破解
$query = "INSERT INTO users (password) VALUES ('$hashed')";

echo "Password hash (MD5): " . $hashed;

// ★★★ 简单加密(XOR) ★★★
// 使用简单的XOR加密消息
function simple_encrypt($message, $key) {
// XOR加密:message XOR key
// 特点:
// 1. 加密和解密使用相同操作
// 2. 非常不安全
// 3. 密钥重用会暴露明文
$result = '';
$keylen = strlen($key);

for ($i = 0; $i < strlen($message); $i++) {
// ★★★ XOR操作 ★★★
// ^ - XOR运算符
// 每个字符与密钥字符进行XOR
$result .= chr(ord($message[$i]) ^ ord($key[$i % $keylen]));
}

return base64_encode($result);
}

// ★★★ 硬编码密钥(极度危险!) ★★★
// 密钥直接写在代码中
// 任何人都可以看到源代码就知道密钥
$encryption_key = "secret";

$message = $_POST['message'] ?? '';
$encrypted = simple_encrypt($message, $encryption_key);

echo "Encrypted message: " . $encrypted;

// ★★★ 解密也很简单 ★★★
function simple_decrypt($encrypted, $key) {
$decoded = base64_decode($encrypted);
return simple_encrypt($decoded, $key); // XOR是对称的
}

?>

MD5哈希示例:

1
2
3
4
5
6
7
8
9
10
11
输入:password123
MD5:482c811da5d5b4bc6d497ffa98491e38

输入:admin
MD5:21232f297a57a5a743894a0e4a801fc3

特点:
1. 固定长度32字符
2. 相同输入总是产生相同输出
3. 不可逆(单向函数)
4. 但可以通过彩虹表反查

漏洞分析

核心问题:

  1. MD5已被攻破

    • 存在碰撞攻击
    • 2004年王小云教授已破解
    • 可以找到两个不同输入产生相同MD5
  2. 无盐(Salt)

    • 相同密码产生相同哈希
    • 容易被彩虹表攻击
  3. XOR加密不安全

    • 密钥重用会暴露明文
    • 已知明文攻击
  4. 硬编码密钥

    • 密钥写在代码中
    • 任何人都可以看到

攻击步骤

步骤1:MD5暴力破解

使用在线工具:

1
2
3
4
5
6
7
8
MD5哈希:5f4dcc3b5aa765d61d8327deb882cf99

在线MD5破解:
- https://crackstation.net/
- https://md5decrypt.net/
- https://www.md5online.org/

结果:password

使用hashcat暴力破解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 准备哈希文件
echo "5f4dcc3b5aa765d61d8327deb882cf99" > hashes.txt

# 使用字典攻击
hashcat -m 0 -a 0 hashes.txt /usr/share/wordlists/rockyou.txt

# -m 0: MD5模式
# -a 0: 字典攻击
# 结果:5f4dcc3b5aa765d61d8327deb882cf99:password

# 暴力破解(纯数字,长度1-8)
hashcat -m 0 -a 3 hashes.txt ?d?d?d?d?d?d?d?d

# ?d: 数字字符集

使用John the Ripper:

1
2
3
4
5
6
7
8
# 准备哈希文件(格式:username:hash)
echo "admin:21232f297a57a57a743894a0e4a801fc3" > hashes.txt

# 破解
john --format=raw-md5 hashes.txt

# 查看结果
john --show hashes.txt

步骤2:彩虹表攻击

什么是彩虹表:

1
2
3
4
5
6
7
8
9
预计算的哈希表:
password → 5f4dcc3b5aa765d61d8327deb882cf99
123456 → e10adc3949ba59abbe56e057f20f883e
admin → 21232f297a57a5a743894a0e4a801fc3
...

查找:
获取哈希:5f4dcc3b5aa765d61d8327deb882cf99
在表中查找 → 找到:password

生成彩虹表:

1
2
3
4
5
# 使用rtgen生成彩虹表
rtgen md5 loweralpha 1 8 0 1000 1000000 0

# 使用rcrack查找
rcrack . -h 5f4dcc3b5aa765d61d8327deb882cf99

步骤3:破解XOR加密

XOR加密原理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
明文:H e l l o
ASCII:72 101 108 108 111

密钥:k e y
ASCII:107 101 121

XOR:
72 ^ 107 = 35 (#)
101 ^ 101 = 0 (NULL)
108 ^ 121 = 21 (控制字符)
108 ^ 107 = 3 (控制字符)
111 ^ 101 = 10 (换行)

密文:Base64(这些字节)

已知密钥破解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import base64

def simple_decrypt(encrypted, key):
decoded = base64.b64decode(encrypted)
result = ''
keylen = len(key)

for i, byte in enumerate(decoded):
result += chr(byte ^ ord(key[i % keylen]))

return result

# 假设我们知道密钥是"secret"
encrypted = "IwQBBQ0A" # Base64编码的密文
key = "secret"

plaintext = simple_decrypt(encrypted, key)
print(f"Decrypted: {plaintext}")

已知明文攻击(Known-Plaintext Attack):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 如果知道一段明文和对应的密文
# 可以恢复密钥

def recover_key(plaintext, ciphertext):
key = ''
decoded = base64.b64decode(ciphertext)

for i in range(len(plaintext)):
# 明文 XOR 密文 = 密钥
key_byte = ord(plaintext[i]) ^ decoded[i]
key += chr(key_byte)

return key

plaintext = "Hello"
ciphertext = "IwQBBQ0A" # 假设这是密文

recovered_key = recover_key(plaintext, ciphertext)
print(f"Recovered key: {recovered_key}")

步骤4:暴力破解短密钥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import base64
import itertools
import string

def try_decrypt(ciphertext, key):
try:
decoded = base64.b64decode(ciphertext)
result = ''
for i, byte in enumerate(decoded):
result += chr(byte ^ ord(key[i % len(key)]))
return result
except:
return None

ciphertext = "IwQBBQ0A"

# 假设密钥是5个小写字母
for key in itertools.product(string.ascii_lowercase, repeat=5):
key_str = ''.join(key)
plaintext = try_decrypt(ciphertext, key_str)

if plaintext and plaintext.isprintable():
print(f"Possible key: {key_str}, plaintext: {plaintext}")

Medium 难度

攻击目标

使用SHA-1哈希和简单的AES加密,仍有弱点。

后端代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?php

// ★★★ Medium难度:使用SHA-1哈希 ★★★

$password = $_POST['password'] ?? '';

// ★★★ 改进:使用SHA-1代替MD5 ★★★
// sha1() - SHA-1哈希函数
// 返回:40位十六进制字符串
//
// 问题:
// 1. SHA-1也已被攻破(2017年Google展示碰撞)
// 2. 仍然没有使用盐
// 3. 速度仍然较快,易于暴力破解
// 4. 不适合密码哈希(应使用bcrypt/Argon2)
$hashed = sha1($password);

echo "Password hash (SHA-1): " . $hashed;

// ★★★ 使用AES加密(但实现有问题) ★★★
// openssl_encrypt() - OpenSSL加密函数

// ★★★ 问题1:硬编码密钥 ★★★
$encryption_key = "mysecretkey12345";

$message = $_POST['message'] ?? '';

// ★★★ 问题2:使用ECB模式 ★★★
// AES-128-ECB - 电子密码本模式
// ECB模式的问题:
// 1. 相同的明文块产生相同的密文块
// 2. 不提供消息完整性保护
// 3. 容易受到块替换攻击
// 4. 不使用IV(初始化向量)
$method = 'AES-128-ECB';

// ★★★ 问题3:密钥长度处理不当 ★★★
// AES-128需要16字节密钥
// 如果密钥不够长,应该使用KDF派生
// 这里只是简单截断或填充
$key = substr(hash('sha256', $encryption_key, true), 0, 16);

// 加密
$encrypted = openssl_encrypt(
$message,
$method,
$key,
OPENSSL_RAW_DATA
);

$encrypted_base64 = base64_encode($encrypted);

echo "Encrypted message (AES-ECB): " . $encrypted_base64;

// 解密
function decrypt_message($encrypted_base64, $encryption_key) {
$method = 'AES-128-ECB';
$key = substr(hash('sha256', $encryption_key, true), 0, 16);

$encrypted = base64_decode($encrypted_base64);

$decrypted = openssl_decrypt(
$encrypted,
$method,
$key,
OPENSSL_RAW_DATA
);

return $decrypted;
}

?>

新增防护

  1. SHA-1替代MD5 - 更强的哈希算法
  2. AES加密 - 标准的对称加密算法
  3. OpenSSL库 - 使用专业的加密库

仍存在的漏洞

核心问题:

  1. SHA-1已被攻破

    • 2017年Google发布SHA-1碰撞
    • 仍然可以暴力破解
  2. ECB模式不安全

    • 相同明文产生相同密文
    • 容易识别模式
  3. 硬编码密钥

    • 密钥仍在代码中
  4. 无盐和迭代

    • 密码哈希应使用bcrypt

绕过方法

方法1:SHA-1暴力破解

1
2
3
4
5
6
# 使用hashcat破解SHA-1
echo "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" > hashes.txt
hashcat -m 100 -a 0 hashes.txt /usr/share/wordlists/rockyou.txt

# -m 100: SHA-1模式
# 结果:5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8:password

方法2:利用ECB模式漏洞

ECB企鹅问题(ECB Penguin):

1
2
3
原始图片 → 使用ECB加密 → 仍能看出轮廓

原因:相同的像素块产生相同的密文块

块替换攻击:

1
2
3
4
5
6
7
8
9
10
11
# 如果知道某些块的明文和密文对应关系
# 可以替换块来修改消息

# 例如:
# 明文:Transfer $100 to Alice
# 密文:[Block1][Block2][Block3][Block4]

# 如果知道"$100"的密文块
# 可以替换成"$999"的密文块

# 这在ECB模式下是可行的

识别ECB模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import base64
from Crypto.Cipher import AES

def detect_ecb(ciphertext):
# ECB模式下,相同的明文块产生相同的密文块
# 检测重复的16字节块

decoded = base64.b64decode(ciphertext)
blocks = [decoded[i:i+16] for i in range(0, len(decoded), 16)]

# 如果有重复块,可能是ECB
if len(blocks) != len(set(blocks)):
return True

return False

ciphertext = "your_base64_ciphertext"
if detect_ecb(ciphertext):
print("Detected ECB mode!")

方法3:密钥恢复(如果可以)

1
2
3
4
5
6
7
# 如果密钥仍然硬编码在可访问的地方
import hashlib

encryption_key = "mysecretkey12345" # 从源代码获取
key = hashlib.sha256(encryption_key.encode()).digest()[:16]

print(f"AES key (hex): {key.hex()}")

High 难度

攻击目标

使用SHA-256和AES-CBC,但仍有实现问题。

后端代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?php

// ★★★ High难度:使用SHA-256哈希 ★★★

$password = $_POST['password'] ?? '';

// ★★★ 改进:使用SHA-256 ★★★
// hash() - 通用哈希函数
// 'sha256' - SHA-256算法
// 返回:64位十六进制字符串
//
// 问题:
// 1. SHA-256虽然更强,但仍不适合密码哈希
// 2. 没有使用盐
// 3. 没有多次迭代(key stretching)
// 4. 应使用password_hash()和bcrypt/Argon2
$hashed = hash('sha256', $password);

echo "Password hash (SHA-256): " . $hashed;

// ★★★ 改进:使用AES-CBC模式 ★★★
// AES-CBC - 密码块链接模式
// 比ECB安全,因为:
// 1. 每个块的加密依赖于前一个块
// 2. 相同的明文块产生不同的密文块
// 3. 使用IV(初始化向量)

// ★★★ 问题1:仍然硬编码密钥 ★★★
$encryption_key = "mysecretkey12345";

// ★★★ 改进:生成随机IV ★★★
// openssl_random_pseudo_bytes() - 生成随机字节
// AES-128-CBC需要16字节IV
$iv = openssl_random_pseudo_bytes(16);

$message = $_POST['message'] ?? '';

$method = 'AES-128-CBC';

// 密钥派生
$key = substr(hash('sha256', $encryption_key, true), 0, 16);

// ★★★ 加密 ★★★
$encrypted = openssl_encrypt(
$message,
$method,
$key,
OPENSSL_RAW_DATA,
$iv // 使用IV
);

// ★★★ 问题2:IV的传输 ★★★
// IV需要和密文一起传输
// IV不需要保密,但必须唯一
// 通常做法:IV + 密文
$encrypted_data = base64_encode($iv . $encrypted);

echo "Encrypted message (AES-CBC): " . $encrypted_data;

// 解密
function decrypt_message($encrypted_data, $encryption_key) {
$method = 'AES-128-CBC';
$key = substr(hash('sha256', $encryption_key, true), 0, 16);

$decoded = base64_decode($encrypted_data);

// ★★★ 提取IV和密文 ★★★
$iv = substr($decoded, 0, 16); // 前16字节是IV
$ciphertext = substr($decoded, 16); // 剩余是密文

$decrypted = openssl_decrypt(
$ciphertext,
$method,
$key,
OPENSSL_RAW_DATA,
$iv
);

return $decrypted;
}

// ★★★ 问题3:缺少消息认证 ★★★
// 没有HMAC验证消息完整性
// 容易受到padding oracle攻击

?>

新增防护

  1. SHA-256 - 更强的哈希算法
  2. AES-CBC模式 - 更安全的分组模式
  3. 随机IV - 每次加密使用不同IV

仍存在的漏洞

核心问题:

  1. 密码哈希不当

    • SHA-256太快,易暴力破解
    • 应使用bcrypt/Argon2
  2. 硬编码密钥

    • 密钥管理不当
  3. 缺少消息认证

    • 没有HMAC
    • 易受Padding Oracle攻击
  4. 密钥派生简单

    • 应使用PBKDF2/HKDF

绕过方法

方法1:SHA-256暴力破解

1
2
3
4
# 虽然SHA-256更强,但仍可以暴力破解弱密码
hashcat -m 1400 -a 0 hashes.txt /usr/share/wordlists/rockyou.txt

# -m 1400: SHA-256模式

方法2:Padding Oracle攻击

什么是Padding Oracle:

1
2
3
4
5
6
7
8
9
10
11
AES-CBC使用PKCS#7填充:
明文长度:13字节
块大小:16字节
填充:3字节(0x03 0x03 0x03

Padding Oracle:
服务器返回不同错误:
- "Invalid padding" → 填充错误
- "Invalid data" → 数据错误

攻击者可以利用这个差异逐字节解密

攻击脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import base64
import requests

def padding_oracle_attack(ciphertext_b64, url):
# 解码密文
decoded = base64.b64decode(ciphertext_b64)
iv = decoded[:16]
ciphertext = decoded[16:]

plaintext = b''

# 对每个块进行攻击
blocks = [ciphertext[i:i+16] for i in range(0, len(ciphertext), 16)]

for block in blocks:
decrypted_block = attack_block(block, iv, url)
plaintext += decrypted_block
iv = block # 下一轮使用当前块作为IV

return plaintext

def attack_block(block, iv, url):
decrypted = b''

# 逐字节破解
for byte_pos in range(16):
for guess in range(256):
# 构造测试IV
test_iv = bytearray(iv)
# ... (复杂的padding oracle逻辑)

# 发送测试请求
response = requests.post(url, data={'ciphertext': base64.b64encode(test_iv + block)})

if 'Invalid padding' not in response.text:
# 找到正确的字节
decrypted = bytes([guess ^ (byte_pos + 1)]) + decrypted
break

return decrypted

方法3:时序攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import time
import statistics

def timing_attack(ciphertext, url):
times = []

for i in range(100):
start = time.time()
response = requests.post(url, data={'ciphertext': ciphertext})
elapsed = time.time() - start
times.append(elapsed)

# 如果响应时间明显不同,可能泄露信息
avg_time = statistics.mean(times)
stddev = statistics.stdev(times)

print(f"Average time: {avg_time:.4f}s, Std Dev: {stddev:.4f}s")

Impossible 难度

攻击目标

使用现代密码学最佳实践,真正安全。

后端代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<?php

// ★★★ Impossible: 使用现代密码学最佳实践 ★★★

$password = $_POST['password'] ?? '';

// ★★★ 核心防护1:使用password_hash() ★★★
// password_hash() - PHP内置的密码哈希函数
// PASSWORD_ARGON2ID - Argon2id算法(最新最安全)
//
// Argon2id的优点:
// 1. 抗GPU/ASIC攻击
// 2. 可配置的内存和时间成本
// 3. 自动生成随机盐
// 4. 内置版本管理
// 5. 2015年密码哈希竞赛冠军
$options = [
'memory_cost' => 65536, // 64MB内存
'time_cost' => 4, // 4次迭代
'threads' => 2 // 2个线程
];

$hashed = password_hash($password, PASSWORD_ARGON2ID, $options);

echo "Password hash (Argon2id): " . $hashed;

// ★★★ 验证密码 ★★★
// password_verify() - 验证密码
// 自动处理盐和算法细节
function verify_password($password, $hash) {
return password_verify($password, $hash);
}

// ★★★ 核心防护2:使用环境变量存储密钥 ★★★
// 不再硬编码密钥
$encryption_key = getenv('ENCRYPTION_KEY');

if (!$encryption_key) {
die('Encryption key not configured');
}

// ★★★ 核心防护3:使用AEAD模式(AES-GCM) ★★★
// AES-GCM - Galois/Counter Mode
// 优点:
// 1. 提供加密和认证
// 2. 防止密文篡改
// 3. 高性能
// 4. 内置消息认证码(MAC)

$message = $_POST['message'] ?? '';

$method = 'aes-256-gcm';

// ★★★ 核心防护4:使用PBKDF2派生密钥 ★★★
// hash_pbkdf2() - 基于密码的密钥派生函数
// 参数:
// - 算法:sha256
// - 密码:原始密钥
// - 盐:随机盐
// - 迭代次数:100000次
// - 密钥长度:32字节(256位)
$salt = random_bytes(16);
$key = hash_pbkdf2(
'sha256',
$encryption_key,
$salt,
100000,
32,
true
);

// ★★★ 生成随机IV ★★★
// AES-256-GCM需要12字节IV(推荐)
$iv = random_bytes(12);

// ★★★ 认证附加数据(AAD) ★★★
// 可选的附加数据,会被认证但不加密
$aad = 'dvwa-message';

// ★★★ 加密 ★★★
$tag = ''; // 认证标签
$encrypted = openssl_encrypt(
$message,
$method,
$key,
OPENSSL_RAW_DATA,
$iv,
$tag, // 输出认证标签
$aad, // 附加认证数据
16 // 标签长度:16字节
);

// ★★★ 组合所有数据 ★★★
// 格式:salt + IV + tag + ciphertext
$encrypted_data = base64_encode($salt . $iv . $tag . $encrypted);

echo "Encrypted message (AES-256-GCM): " . $encrypted_data;

// ★★★ 解密函数 ★★★
function decrypt_message($encrypted_data, $encryption_key) {
$method = 'aes-256-gcm';
$decoded = base64_decode($encrypted_data);

// ★★★ 提取各个部分 ★★★
$salt = substr($decoded, 0, 16); // 盐:16字节
$iv = substr($decoded, 16, 12); // IV:12字节
$tag = substr($decoded, 28, 16); // 标签:16字节
$ciphertext = substr($decoded, 44); // 剩余:密文

// ★★★ 重新派生密钥 ★★★
$key = hash_pbkdf2(
'sha256',
$encryption_key,
$salt,
100000,
32,
true
);

// ★★★ AAD必须相同 ★★★
$aad = 'dvwa-message';

// ★★★ 解密并验证 ★★★
$decrypted = openssl_decrypt(
$ciphertext,
$method,
$key,
OPENSSL_RAW_DATA,
$iv,
$tag, // 验证认证标签
$aad
);

// ★★★ 如果认证失败,返回false ★★★
if ($decrypted === false) {
throw new Exception('Decryption failed: Message authentication failed');
}

return $decrypted;
}

// ★★★ 额外安全措施 ★★★

// 1. 密钥轮换
function rotate_key_if_needed() {
$key_age = time() - getenv('KEY_CREATED_TIME');
$max_age = 30 * 24 * 3600; // 30天

if ($key_age > $max_age) {
// 触发密钥轮换流程
trigger_key_rotation();
}
}

// 2. 审计日志
function log_crypto_operation($operation, $success) {
$log = [
'timestamp' => date('Y-m-d H:i:s'),
'operation' => $operation,
'success' => $success,
'user' => dvwaCurrentUser(),
'ip' => $_SERVER['REMOTE_ADDR']
];

file_put_contents(
'/var/log/security/crypto.log',
json_encode($log) . "\n",
FILE_APPEND
);
}

?>

完善的防护机制

多层防御:

  1. Argon2id密码哈希 - 抗暴力破解
  2. 环境变量密钥 - 不硬编码
  3. AES-GCM AEAD - 加密+认证
  4. PBKDF2密钥派生 - 强密钥派生
  5. 随机盐和IV - 每次都不同
  6. 认证标签 - 防止篡改
  7. 密钥轮换 - 定期更换密钥
  8. 审计日志 - 记录所有操作

安全流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
密码哈希:
用户密码 → Argon2id(password, random_salt, options)
→ 存储哈希

验证:
输入密码 → password_verify(input, stored_hash)
True/False

加密:
明文 + 密钥(环境变量)
→ PBKDF2派生实际密钥
→ AES-256-GCM加密
→ 生成认证标签
→ 输出:salt + IV + tag + ciphertext

解密:
接收:salt + IV + tag + ciphertext
→ PBKDF2派生密钥
→ AES-256-GCM解密
→ 验证认证标签
→ 成功:明文,失败:拒绝

为什么无法攻破?

所有攻击都失败:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
攻击1:暴力破解密码
Argon2id → 需要大量内存和时间
64MB内存 × 4次迭代 → 暴力破解不可行

攻击2:彩虹表
随机盐 → 每个密码都有唯一哈希
彩虹表无效

攻击3:篡改密文
AES-GCM认证标签 → 任何修改都会导致验证失败

攻击4Padding Oracle
AES-GCM不使用填充 → 不存在padding oracle

攻击5:ECB模式攻击
使用GCM模式 → ECB漏洞不存在

攻击6:获取密钥
环境变量 → 不在代码中
即使获取密文,没有密钥无法解密

防御建议

密码哈希最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ✅ 正确:使用password_hash()
$hash = password_hash($password, PASSWORD_ARGON2ID, [
'memory_cost' => 65536,
'time_cost' => 4,
'threads' => 2
]);

// 验证
if (password_verify($input_password, $hash)) {
// 密码正确
}

// ❌ 错误
$hash = md5($password);
$hash = sha1($password);
$hash = hash('sha256', $password);

加密最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ✅ 正确:使用AEAD模式
function encrypt_message($plaintext, $key) {
$method = 'aes-256-gcm';
$iv = random_bytes(12);
$tag = '';

$ciphertext = openssl_encrypt(
$plaintext,
$method,
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);

return base64_encode($iv . $tag . $ciphertext);
}

// ❌ 错误
// - 使用ECB模式
// - 硬编码密钥
// - 不使用IV
// - 不验证消息完整性

密钥管理

1
2
3
4
5
6
7
8
# 使用环境变量
export ENCRYPTION_KEY=$(openssl rand -hex 32)
export DATABASE_KEY=$(openssl rand -hex 32)

# 或使用密钥管理服务(KMS)
# - AWS KMS
# - Azure Key Vault
# - HashiCorp Vault

随机数生成

1
2
3
4
5
6
7
8
// ✅ 正确:密码学安全的随机数
$random = random_bytes(32);
$random = openssl_random_pseudo_bytes(32);

// ❌ 错误:不安全的随机数
$random = rand();
$random = mt_rand();
$random = uniqid();

总结对比

特性 Low Medium High Impossible
密码哈希 MD5 SHA-1 SHA-256 Argon2id
盐(Salt) ✅ 自动
加密算法 XOR AES-ECB AES-CBC AES-GCM
IV
消息认证 ✅ AEAD
密钥管理 硬编码 硬编码 硬编码 环境变量
密钥派生 简单hash 简单hash PBKDF2
攻击难度 极易 简单 中等 极难

常用工具

密码破解

1
2
3
4
5
6
7
8
# Hashcat
hashcat -m 0 hashes.txt wordlist.txt # MD5
hashcat -m 100 hashes.txt wordlist.txt # SHA-1
hashcat -m 1400 hashes.txt wordlist.txt # SHA-256

# John the Ripper
john --format=raw-md5 hashes.txt
john --format=raw-sha1 hashes.txt

加密分析

1
2
3
4
5
6
# 检测ECB模式
from Crypto.Cipher import AES

def is_ecb(ciphertext):
blocks = [ciphertext[i:i+16] for i in range(0, len(ciphertext), 16)]
return len(blocks) != len(set(blocks))

实战建议

渗透测试:

  1. ✅ 识别哈希算法(长度、格式)
  2. ✅ 尝试彩虹表/暴力破解
  3. ✅ 检测加密模式(ECB/CBC)
  4. ✅ 查找硬编码密钥
  5. ✅ 测试Padding Oracle
  6. ✅ 分析随机数质量

防御清单:

  1. ✅ 使用Argon2id/bcrypt哈希密码
  2. ✅ 使用AES-GCM等AEAD模式
  3. ✅ 密钥存储在环境变量/KMS
  4. ✅ 使用PBKDF2派生密钥
  5. ✅ 使用random_bytes()生成随机数
  6. ✅ 定期密钥轮换
  7. ✅ 审计所有密码学操作

道德准则:

  • 只在授权环境测试
  • 不破解真实用户密码
  • 学习是为了构建安全系统
点这里请我吃个小蛋糕吧~~

Welcome to my other publishing channels