前置知识: 网络安全

密码哈希

2 min中级

密码哈希命令实操:bcrypt/Argon2/scrypt/PBKDF2 生成与验证、Linux crypt 哈希、Django/Spring/Node.js 框架实践与参数基线。

为什么密码要用专用哈希

普通哈希(SHA-256)计算太快,GPU 每秒可算数十亿次,攻击者拿库后可离线穷举。 密码哈希函数(bcrypt/Argon2/scrypt/PBKDF2)的共同点是刻意缓慢且消耗资源、 强制加盐,把单次验证成本抬高到对用户无感、对爆破者致命的水平。原理与算法对比 见 017-HashAlgorithm 第 6 节;本文聚焦各平台可复制的命令。

bcrypt 哈希

基本写法:使用 Python 生成 bcrypt 哈希 python3 -c "import bcrypt; print(bcrypt.hashpw(b'<密码>', bcrypt.gensalt()).decode())"

# 生成 bcrypt 哈希
python3 -c "import bcrypt; print(bcrypt.hashpw(b'mypassword', bcrypt.gensalt(12)).decode())"

基本写法:指定计算成本 python3 -c "import bcrypt; print(bcrypt.hashpw(b'<密码>', bcrypt.gensalt(<成本>)).decode())"

# 使用成本因子 12(默认 12)
python3 -c "import bcrypt; print(bcrypt.hashpw(b'mypassword', bcrypt.gensalt(14)).decode())"

基本写法:验证 bcrypt 密码 python3 -c "import bcrypt; print(bcrypt.checkpw(b'<密码>', b'<哈希>'))"

# 验证 bcrypt 密码
python3 -c "import bcrypt; print(bcrypt.checkpw(b'mypassword', b'\$2b\$12\$...'))"

基本写法:使用 htpasswd 生成 bcrypt htpasswd -nbB <用户> <密码>

# 使用 Apache htpasswd 生成 bcrypt
htpasswd -nbB admin secret123

基本写法:使用 Node.js 生成 bcrypt node -e "const bcrypt=require('bcrypt'); console.log(bcrypt.hashSync('密码', 12))"

# Node.js 生成 bcrypt
node -e "const bcrypt=require('bcrypt'); console.log(bcrypt.hashSync('mypassword', 12))"

Argon2 哈希

基本写法:使用 argon2 命令行工具 argon2 <盐> -id -t <迭代次数> -m <内存(2的幂)> -p <并行数> -l <长度>

# 注意:-m N 表示内存为 2^N KiB,-m 16 即 64MiB(不是 65536)
echo -n "mypassword" | argon2 somesalt -id -t 3 -m 16 -p 1 -l 32
# 命令行传盐仅适合实验;生产请用库函数自动生成随机盐(见下方 Python 示例)

基本写法:使用 Python argon2 python3 -c "from argon2 import PasswordHasher; ph=PasswordHasher(); print(ph.hash('<密码>'))"

# 使用 argon2-cffi 库
python3 -c "from argon2 import PasswordHasher; ph=PasswordHasher(); print(ph.hash('mypassword'))"

基本写法:验证 argon2 密码 python3 -c "from argon2 import PasswordHasher; ph=PasswordHasher(); print(ph.verify('<哈希>', '<密码>'))"

# 验证 argon2 密码
python3 -c "from argon2 import PasswordHasher; ph=PasswordHasher(); print(ph.verify('\$argon2id\$...', 'mypassword'))"

基本写法:使用 Node.js argon2 node -e "const argon2=require('argon2'); argon2.hash('密码').then(console.log)"

# Node.js 生成 argon2
node -e "const argon2=require('argon2'); argon2.hash('mypassword').then(console.log)"

PBKDF2 哈希

基本写法:使用 Python PBKDF2 python3 -c "import hashlib, binascii, os; salt=os.urandom(16); print(binascii.hexlify(hashlib.pbkdf2_hmac('sha256', b'<密码>', salt, <迭代次数>)).decode())"

# 使用 PBKDF2-SHA256 派生密钥
python3 -c "import hashlib, binascii, os; salt=os.urandom(16); print(binascii.hexlify(hashlib.pbkdf2_hmac('sha256', b'mypassword', salt, 600000)).decode())"

基本写法:使用 OpenSSL PBKDF2 openssl kdf -keylen <长度> -kdfopts pass:<密码>:salt:<盐>:iter:<迭代次数> PBKDF2

# OpenSSL 生成 PBKDF2 密钥
openssl kdf -keylen 32 -kdfopts pass:password:salt:salt:iter:600000 PBKDF2

基本写法:使用 Django PBKDF2 python3 -c "from django.contrib.auth.hashers import PBKDF2PasswordHasher; h=PBKDF2PasswordHasher(); print(h.encode('<密码>', h.salt()))"

# Django 风格 PBKDF2 哈希
python3 -c "from django.contrib.auth.hashers import PBKDF2PasswordHasher; h=PBKDF2PasswordHasher(); print(h.encode('mypassword', h.salt()))"

scrypt 哈希

基本写法:使用 OpenSSL scrypt openssl kdf -keylen <长度> -kdfopts pass:<密码>:salt:<盐>:n:<N>:r:<r>:p:<p> scrypt

# 使用 scrypt 派生密钥
openssl kdf -keylen 32 -kdfopts pass:password:salt:salt:n:16384:r:8:p:1 scrypt

基本写法:使用 Python scrypt python3 -c "import hashlib; print(hashlib.scrypt(b'<密码>', salt=b'<盐>', n=16384, r=8, p=1, dklen=32).hex())"

# Python 生成 scrypt 哈希
python3 -c "import hashlib; print(hashlib.scrypt(b'mypassword', salt=b'salt', n=16384, r=8, p=1, dklen=32).hex())"

基本写法:使用 Node.js scrypt node -e "const crypto=require('crypto'); console.log(crypto.scryptSync('密码', '盐', 64).toString('hex'))"

# Node.js 生成 scrypt 哈希
node -e "const crypto=require('crypto'); console.log(crypto.scryptSync('mypassword', 'salt', 64).toString('hex'))"

Linux 系统密码哈希

基本写法:使用 mkpasswd mkpasswd -m <算法> <密码>

# 生成 SHA-512 密码哈希
mkpasswd -m sha-512 mypassword

基本写法:使用 openssl 生成 crypt 哈希 openssl passwd -6 <密码>

# 生成 SHA-512crypt 哈希
openssl passwd -6 mypassword

基本写法:使用 openssl 生成 bcrypt openssl passwd -bcrypt <密码>

# 生成 bcrypt 哈希
openssl passwd -bcrypt mypassword

基本写法:使用 Python crypt python3 -c "import crypt; print(crypt.crypt('<密码>', crypt.mksalt(crypt.METHOD_SHA512)))"

# 生成 SHA-512crypt 密码哈希
# 注意:crypt 模块在 Python 3.13 中已被移除(3.11 起弃用),
# 新代码请改用 passlib 或直接调用 openssl passwd
python3 -c "import crypt; print(crypt.crypt('mypassword', crypt.mksalt(crypt.METHOD_SHA512)))"

密码哈希验证

基本写法:使用 Python crypt 验证 python3 -c "import crypt; print(crypt.crypt('<密码>', '<哈希>') == '<哈希>')"

# 验证密码哈希
python3 -c "import crypt; print(crypt.crypt('mypassword', '\$6\$...') == '\$6\$...')"

基本写法:使用 openssl 验证 openssl passwd -6 -salt <盐> <密码>

# 验证密码哈希
openssl passwd -6 -salt abc123 mypassword

基本写法:使用 htpasswd 验证 htpasswd -bv <密码文件> <用户> <密码>

# 验证 htpasswd 中的密码
htpasswd -bv /etc/nginx/.htpasswd admin secret123

Django 密码哈希

基本写法:使用 Django 生成密码哈希 python3 -c "from django.contrib.auth.hashers import make_password; print(make_password('<密码>'))"

# Django 生成 PBKDF2 密码哈希
python3 -c "from django.contrib.auth.hashers import make_password; print(make_password('mypassword'))"

基本写法:使用 Django 验证密码 python3 -c "from django.contrib.auth.hashers import check_password; print(check_password('<密码>', '<哈希>'))"

# Django 验证密码
python3 -c "from django.contrib.auth.hashers import check_password; print(check_password('mypassword', 'pbkdf2_sha256\$...'))"

基本写法:使用 Django Argon2 python3 -c "from django.contrib.auth.hashers import make_password; print(make_password('<密码>', hasher='argon2'))"

# Django 使用 Argon2 哈希
python3 -c "from django.contrib.auth.hashers import make_password; print(make_password('mypassword', hasher='argon2'))"

Spring Security 密码编码

基本写法:使用 BCryptPasswordEncoder

`BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String hash = encoder.encode("密码");
boolean match = encoder.matches("密码", hash);`
// Spring Security BCrypt 编码
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
String hash = encoder.encode("mypassword");
boolean match = encoder.matches("mypassword", hash);

基本写法:使用 Argon2PasswordEncoder

`Argon2PasswordEncoder encoder = new Argon2PasswordEncoder();
String hash = encoder.encode("密码");`
// Spring Security Argon2 编码
Argon2PasswordEncoder encoder = new Argon2PasswordEncoder();
String hash = encoder.encode("mypassword");

Node.js 密码哈希

基本写法:使用 bcrypt node -e "const bcrypt=require('bcrypt'); bcrypt.hash('密码', 12).then(console.log)"

# Node.js bcrypt 哈希
node -e "const bcrypt=require('bcrypt'); bcrypt.hash('mypassword', 12).then(console.log)"

基本写法:验证 bcrypt node -e "const bcrypt=require('bcrypt'); bcrypt.compare('密码', '哈希').then(console.log)"

# Node.js 验证 bcrypt
node -e "const bcrypt=require('bcrypt'); bcrypt.compare('mypassword', '\$2b\$...').then(console.log)"

基本写法:使用 scrypt node -e "const crypto=require('crypto'); const hash=crypto.scryptSync('密码','盐',64).toString('hex'); console.log(hash)"

# Node.js 内置 scrypt
node -e "const crypto=require('crypto'); const hash=crypto.scryptSync('mypassword','salt',64).toString('hex'); console.log(hash)"

密码强度检测

基本写法:检查密码长度 python3 -c "p='<密码>'; print(len(p) >= 12 and '足够' or '不足')"

# 检查密码长度是否至少 12 位
python3 -c "p='mypassword'; print('OK' if len(p) >= 12 else 'Too short')"

基本写法:检查密码复杂度 python3 -c "import re; p='<密码>'; print(bool(re.match(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@\$!%*?&]).{12,}$', p)))"

# 检查密码是否包含大小写字母数字特殊字符
python3 -c "import re; p='MyP@ssw0rd2026'; print(bool(re.match(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@\$!%*?&]).{12,}$', p)))"

基本写法:使用 passlib 检测 python3 -c "from passlib.hash import bcrypt; print(bcrypt.using(rounds=12).hash('<密码>'))"

# 使用 passlib 库生成 bcrypt
python3 -c "from passlib.hash import bcrypt; print(bcrypt.using(rounds=12).hash('mypassword'))"

密码哈希最佳实践

基本写法:推荐算法对比

`算法       推荐参数                  说明
Argon2id   memory=64MB, iter=3      首选,抗 GPU/ASIC
bcrypt     cost=12+                 成熟可靠
scrypt     N=16384, r=8, p=1        内存困难函数
PBKDF2     iterations=600000+       兼容性最好但较弱`
# 密码哈希算法推荐顺序
1. Argon2id(PHC 竞赛冠军,当前首选)
2. bcrypt(成熟,cost >= 12;密码最长 72 字节需注意)
3. scrypt(内存困难,N=16384)
4. PBKDF2(兼容性,迭代 >= 600000;FIPS 环境下的合规选择,见 NIST SP 800-132)
# 注意:Argon2 并非 FIPS 认证算法(FIPS 203 是后量子算法 ML-KEM,勿混淆);
# 需过 FIPS 合规审计的系统选 PBKDF2

基本写法:弱算法警告

`已废弃:MD5、SHA1、DES、3DES、RC4
不推荐:直接使用 SHA256 哈希密码
推荐:使用专门的密码哈希函数 bcrypt/Argon2`
# 检查 /etc/shadow 中的哈希算法
grep $USER /etc/shadow | cut -d: -f2 | cut -d$ -f2