hashlib 是 Python 标准库里做**哈希(hash)/摘要(digest)的核心模块:把任意长度数据映射成固定长度的"指纹"。它常用于完整性校验、去重、签名/认证、密码存储(不推荐直接用 hashlib 原生哈希)**等。
牢记一句话:哈希 ≠ 加密。哈希通常不可逆;加密是可逆的。
1)hashlib里常见算法
MD5
- 输出长度:128 bit(32 hex)
- 特点 :快、老、已不安全(可碰撞)
- 适用:非安全场景的快速校验/去重(例如文件变更检测、缓存 key)
- 不适用:签名、防篡改、安全校验、密码
SHA-1
- 输出长度:160 bit(40 hex)
- 特点 :已不安全(可碰撞)
- 适用:兼容遗留系统(不得已)
- 不适用:安全校验、签名、认证
SHA-2 系列:SHA-224 / SHA-256 / SHA-384 / SHA-512
- 输出长度:分别 224/256/384/512 bit
- 特点:通用、可靠、生态最好(目前主流安全哈希)
- 适用:文件校验、防篡改、签名摘要、内容寻址、token 摘要
- 选型 :
- SHA-256:最常用默认选
- SHA-512:在 64 位平台可能更快,摘要更长
SHA-3 系列:SHA3-224 / SHA3-256 / SHA3-384 / SHA3-512
- 特点:新标准(Keccak 结构),与 SHA-2 不同家族
- 适用:需要 SHA-3 标准的场景;或想要与 SHA-2 "多样化"风险隔离
- 注意:并不一定比 SHA-2 更快,主要是标准与结构差异
BLAKE2:blake2b / blake2s
- 特点 :非常快、安全、支持 key(可做 MAC)、支持自定义摘要长度
- 适用:高性能内容哈希、去重、分片校验、带 key 的认证哈希
- 选型 :
- blake2b:适合 64 位平台(通用推荐)
- blake2s:适合 32 位平台/嵌入式倾向
shake_128 / shake_256(XOF:可变长度输出)
- 特点:你想要多长摘要就输出多长
- 适用:协议/研究/需要可变长度摘要的工程
- 一般业务:用 SHA-256 / BLAKE2 就够了
2)快速对比:该怎么选?
| 目标 | 推荐算法 | 原因 |
|---|---|---|
| 文件完整性校验(下载包、镜像、模型权重) | SHA-256 / BLAKE2b | 安全、通用;BLAKE2 更快 |
| 内容去重 / 缓存 key(不做安全对抗) | BLAKE2b / SHA-256 | 性能好;避免 MD5/SHA1 的坏习惯 |
| 防篡改签名的摘要(配合 RSA/ECDSA/EdDSA) | SHA-256(最常见) | 生态最好 |
| 认证(消息鉴别) | HMAC-SHA256 或 BLAKE2(key=...) | 抗长度扩展/可作为 MAC |
| 密码存储 | 不用 hashlib 直接 hash | 需要慢哈希(bcrypt/scrypt/argon2/pbkdf2) |
3)基础示例:字符串 / bytes 哈希
python
import hashlib
data = "hello world".encode("utf-8")
print("md5 :", hashlib.md5(data).hexdigest())
print("sha1 :", hashlib.sha1(data).hexdigest())
print("sha256 :", hashlib.sha256(data).hexdigest())
print("sha3_256:", hashlib.sha3_256(data).hexdigest())
print("blake2b :", hashlib.blake2b(data).hexdigest())
4)大文件哈希:分块读取(推荐写法)
适合模型权重、视频、压缩包等大文件,不会一次性读入内存。
python
import hashlib
from pathlib import Path
def file_hash(path: str, algo: str = "sha256", chunk_size: int = 1024 * 1024) -> str:
h = hashlib.new(algo)
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(chunk_size), b""):
h.update(chunk)
return h.hexdigest()
p = "big_file.bin"
print("sha256:", file_hash(p, "sha256"))
print("blake2b:", file_hash(p, "blake2b"))
5)HMAC:认证哈希(不要自己"拼接 secret")
如果你要做"请求签名 / 回调验签 / API token 校验",推荐 HMAC。
python
import hmac
import hashlib
secret = b"my-secret-key"
msg = b"timestamp=1700000000&user_id=123"
sig = hmac.new(secret, msg, hashlib.sha256).hexdigest()
print("signature:", sig)
# 校验时用 compare_digest 防时序侧信道
ok = hmac.compare_digest(sig, hmac.new(secret, msg, hashlib.sha256).hexdigest())
print("verify:", ok)
6)BLAKE2 直接带 key:轻量 MAC(很实用)
python
import hashlib
key = b"my-secret-key"
msg = b"payload"
mac = hashlib.blake2b(msg, key=key, digest_size=32).hexdigest()
print("blake2b mac:", mac)
7)密码存储:用 hashlib.pbkdf2_hmac(标准库可用)
不要 用 sha256(password) 存密码。最少用 PBKDF2(更推荐 argon2/bcrypt/scrypt,但那是第三方库)。
python
import os
import hashlib
import hmac
from base64 import b64encode, b64decode
def hash_password_pbkdf2(password: str, iterations: int = 200_000) -> str:
salt = os.urandom(16)
dk = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, iterations, dklen=32)
return f"pbkdf2_sha256${iterations}${b64encode(salt).decode()}${b64encode(dk).decode()}"
def verify_password_pbkdf2(password: str, stored: str) -> bool:
scheme, iters, salt_b64, dk_b64 = stored.split("$")
assert scheme == "pbkdf2_sha256"
iterations = int(iters)
salt = b64decode(salt_b64)
dk_expected = b64decode(dk_b64)
dk = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, iterations, dklen=len(dk_expected))
return hmac.compare_digest(dk, dk_expected)
stored = hash_password_pbkdf2("P@ssw0rd")
print("stored:", stored)
print("verify ok:", verify_password_pbkdf2("P@ssw0rd", stored))
print("verify no:", verify_password_pbkdf2("wrong", stored))
8)常见坑与建议(很短但很关键)
- 不要用 MD5 / SHA-1 做安全相关(签名、验篡改、认证、密码都不行)。
- 做"签名/验签"时,别用
hash(secret + msg)这种自制方案 ,用 HMAC。 - 校验签名时用
hmac.compare_digest,避免时序攻击。 - 文件校验:SHA-256 或 BLAKE2b,大文件用分块读取。
- 密码:标准库就用
pbkdf2_hmac;追求更强更省心用第三方argon2-cffi。
9)一句话总结选型
- 默认:SHA-256
- 更快:BLAKE2b
- 认证:HMAC-SHA256 或 BLAKE2(key=...)
- 密码:PBKDF2(或 argon2/bcrypt/scrypt)