在数据处理、密码校验、文件完整性验证等场景中,哈希算法几乎是绕不开的技术。Python标准库中的hashlib模块封装了MD5、SHA1、SHA256、SHA512等常见哈希算法,无需安装第三方依赖即可直接使用。本文详细介绍hashlib的常用方法、文件哈希计算、加盐处理以及算法选型建议。

一、hashlib模块基础用法
hashlib的核心思路是先创建一个哈希对象,然后不断喂入数据,最后通过hexdigest()或digest()方法获取结果。最简单的场景是对一个字符串计算MD5值:
import hashlib
# 要加密的内容必须是字节类型,字符串需要先编码
text = "hello world"
md5_obj = hashlib.md5(text.encode("utf-8"))
result = md5_obj.hexdigest()
print(result)
# 输出: 5eb63bbbe01eeed093cb22bb8f5acdc3有两点需要特别注意。第一,update()方法接收的必须是bytes类型,如果传入字符串会直接抛出TypeError,所以一定要调用encode()先编码。第二,hexdigest()返回的是十六进制字符串,而digest()返回原始的二进制数据,日常使用中前者更常见,方便存储和比对。
除了直接传入初始数据,也可以分多次调用update(),效果等同于把所有数据拼接后一次性计算。这种写法在处理流式数据时非常实用:
import hashlib
m = hashlib.md5()
m.update("hello ".encode("utf-8"))
m.update("world".encode("utf-8"))
print(m.hexdigest())
# 输出结果与一次性计算相同: 5eb63bbbe01eeed093cb22bb8f5acdc3二、SHA系列算法的使用
SHA家族包括SHA1、SHA224、SHA256、SHA384、SHA512等多个变体,用法与MD5完全一致,只是构造函数不同:
import hashlib
text = "hello world".encode("utf-8")
print(hashlib.sha1(text).hexdigest())
# 输出: 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
print(hashlib.sha256(text).hexdigest())
# 输出: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
print(hashlib.sha512(text).hexdigest())
# 输出: 128位长度的十六进制字符串不同算法的主要区别体现在摘要长度和安全性上。MD5输出128位(32个十六进制字符),SHA1输出160位(40个字符),SHA256输出256位(64个字符)。摘要越长,理论上碰撞的可能性越低,安全性也就越高。可以通过hashlib.algorithms_available查看当前Python环境支持的所有算法,通过hashlib.algorithms_guaranteed查看所有平台都保证支持的算法。
Python 3.6之后还引入了hashlib.new()的另一种用法和更简洁的shake系列,同时提供了usedforsecurity参数。如果只需要判断两个文件是否相同,而不需要考虑加密强度,MD5的性能优势依然明显,因为它的计算速度比SHA256快不少。
三、大文件的哈希计算
计算文件哈希时最容易犯的错误是把整个文件一次性读入内存。对于几个GB的日志文件或视频文件,这种做法会导致内存暴涨甚至程序崩溃。正确的做法是分块读取,反复调用update():
import hashlib
def file_hash(filepath, algo="md5", chunk_size=8192):
h = hashlib.new(algo)
with open(filepath, "rb") as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
h.update(chunk)
return h.hexdigest()
print(file_hash("C:\\test\\bigfile.zip", "sha256"))这段代码每次只读取8KB数据,内存占用恒定,无论文件多大都能稳定运行。块大小可以自行调整,一般8KB到1MB之间都比较合适,读取太快反而可能增加CPU调度开销。
这个函数在文件校验场景中非常实用。比如下载完一个安装包后,对比官方公布的SHA256值就能确认文件是否被篡改或下载损坏。批量比对时建议封装成函数并打印进度,避免长时间无响应。
四、加盐与安全实践
直接对密码做MD5存储是非常危险的。MD5早已被证实可以通过彩虹表快速反查,简单密码几乎秒破。正确的做法是加盐(salt),即在密码前后拼接一段随机字符串再计算哈希:
import hashlib
import os
password = "123456"
salt = os.urandom(16).hex() # 每次生成随机盐值
salted = password + salt
hashed = hashlib.sha256(salted.encode("utf-8")).hexdigest()
print("盐值:", salt)
print("哈希结果:", hashed)盐值需要与哈希结果一起存储在数据库中,用户登录时取出盐值重新计算并比对。由于每个用户的盐都不同,攻击者无法使用通用的彩虹表批量破解。不过手工加盐只是基础做法,如果项目对安全性要求较高,更推荐使用专门的密码哈希方案,例如标准库中的hashlib.pbkdf2_hmac或者第三方库bcrypt、argon2,它们通过多次迭代大幅增加暴力破解的成本:
import hashlib
password = "123456".encode("utf-8")
salt = b"random_salt_bytes"
# 迭代10万次,使用SHA256作为底层算法
dk = hashlib.pbkdf2_hmac("sha256", password, salt, 100000)
print(dk.hex())总结一下选型建议:文件完整性校验用MD5或SHA256都行;密码存储绝对不要用裸MD5,至少加盐加迭代,最好直接上bcrypt;接口签名常用MD5配合密钥,安全性要求高则换SHA256。掌握hashlib这些用法后,绝大多数哈希相关需求都能轻松应对。
Python hashlibMD5加密SHA256哈希修改时间:2026-09-15 15:20:44