前言
开发中经常遇到加密需求:接口签名、密码摘要、文件校验、数据防篡改等场景,SHA 系列哈希算法使用极其广泛。
很多新手容易混淆几个常见误区:
- SHA 不是加密,是哈希摘要算法,不可逆,无法解密;
- 直接对中文字符串加密经常出现报错;
- 分不清 SHA1、SHA256、SHA512 使用场景;
- 不知道加盐哈希该如何实现。
本文基于 Python 内置 hashlib 库,无需额外安装第三方包,完整演示各类 SHA 哈希实现,附带常见踩坑解决方案。
环境说明:Python3.6+ 原生支持,Windows / Linux / Mac 通用。
一、基础概念区分
- SHA(Secure Hash Algorithm)安全哈希算法
- SHA1:输出160位(40位十六进制字符串),安全性较弱,新项目不推荐;
- SHA256:输出256位(64位十六进制),目前业务最常用;
- SHA512:输出512位(128位十六进制),安全性更高;
- 重要特性
- 单向不可逆:只能生成摘要,不能反向还原原始内容;
- 雪崩效应:原始内容微小改动,摘要完全不同;
- 相同输入一定得到相同摘要;
- 注意:哈希 ≠ 加密。加密可以解密,哈希无法解密。
二、基础环境:内置 hashlib
不需要 pip install,Python 自带:
python
import hashlib
三、最简单示例:字符串 SHA256 摘要
⚠️ 关键点:hashlib 只支持 bytes 字节流,字符串必须先 .encode(),推荐编码 utf-8。
python
import hashlib
def get_sha256(text: str) -> str:
# 1. 字符串转字节
data = text.encode("utf-8")
# 2. 创建sha256对象
sha_obj = hashlib.sha256(data)
# 3. 获取十六进制摘要
result = sha_obj.hexdigest()
return result
if __name__ == "__main__":
content = "hello world"
res = get_sha256(content)
print("SHA256摘要:", res)
输出结果:
SHA256摘要: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
四、SHA1、SHA512 通用写法
只需要更换 hashlib.sha1()、hashlib.sha512()
python
import hashlib
text = "测试文本123"
data = text.encode("utf-8")
sha1_res = hashlib.sha1(data).hexdigest()
sha256_res = hashlib.sha256(data).hexdigest()
sha512_res = hashlib.sha512(data).hexdigest()
print("SHA1:", sha1_res)
print("SHA256:", sha256_res)
print("SHA512:", sha512_res)
五、进阶:分段大文件 SHA 哈希(适合校验文件完整性)
如果文件很大,一次性读取全部内容占用内存,采用分段更新 update()。
python
import hashlib
def get_file_sha256(file_path: str, chunk_size=4096) -> str:
sha_obj = hashlib.sha256()
with open(file_path, "rb") as f:
while chunk := f.read(chunk_size):
sha_obj.update(chunk)
return sha_obj.hexdigest()
# 使用
# print(get_file_sha256("test.zip"))
六、业务常用:加盐 SHA 摘要
直接 SHA 存在彩虹表碰撞风险,存储密码、接口签名建议加盐 。
两种主流方式:
python
import hashlib
def get_sha256_salt(text: str, salt: str = "my_secret_2026") -> str:
# 方式1:原始内容 + 盐拼接
raw = text + salt
return hashlib.sha256(raw.encode("utf-8")).hexdigest()
# 推荐:盐放在前后都可以,前后位置保持和服务端一致即可
print(get_sha256_salt("123456"))
重要提醒:加盐规则前后端必须完全统一,拼接顺序、编码不一致会导致摘要不匹配。
七、digest() 与 hexdigest() 区别
很多新手分不清这两个方法:
.hexdigest():返回十六进制字符串,日常接口、日志打印首选;.digest():返回原始二进制字节串,一般极少直接使用。
python
data = "demo".encode("utf-8")
print(hashlib.sha256(data).hexdigest()) # 字符串
print(hashlib.sha256(data).digest()) # bytes
八、高频踩坑清单
坑1:中文不编码直接加密,抛异常
python
# 错误写法
# hashlib.sha256("中文")
# TypeError: Unicode-objects must be encoded before hashing
# 正确:必须encode
hashlib.sha256("中文".encode("utf-8"))
坑2:编码不一致导致摘要不同
同一文本,一方 utf-8,一方 gbk,算出的 sha256 完全不一样。
项目统一约定:全部使用 utf-8。
坑3:SHA1 安全性不足
SHA1 已被证明存在碰撞漏洞,新项目禁止使用 SHA1 做签名、密码存储,优先 SHA256。
坑4:哈希用来存储密码不推荐
单纯 SHA256+简单盐依然不安全。用户密码存储推荐使用 bcrypt / passlib,内置多次迭代加盐。SHA 更适合接口签名、文件校验场景。
坑5:空格、换行、不可见字符引发摘要不一致
网络传输时,注意去除首尾多余空格,保证参与哈希的原始文本完全一致。
九、封装通用工具类(可直接放入项目)
python
import hashlib
class HashUtil:
@staticmethod
def sha1(text: str, encoding="utf-8") -> str:
return hashlib.sha1(text.encode(encoding)).hexdigest()
@staticmethod
def sha256(text: str, encoding="utf-8") -> str:
return hashlib.sha256(text.encode(encoding)).hexdigest()
@staticmethod
def sha512(text: str, encoding="utf-8") -> str:
return hashlib.sha512(text.encode(encoding)).hexdigest()
@staticmethod
def sha256_salt(text: str, salt: str, encoding="utf-8") -> str:
content = text + salt
return hashlib.sha256(content.encode(encoding)).hexdigest()
if __name__ == "__main__":
print(HashUtil.sha256("hello python"))
十、常见业务场景选型建议
- 接口请求签名:SHA256 + 自定义盐(前后端约定拼接规则)
- 文件完整性校验:SHA256 / SHA512
- 日志数据摘要标识:SHA256
- 旧系统兼容:SHA1(新项目尽量规避)
总结
- Python 使用内置
hashlib实现 SHA 系列哈希,无需第三方库; - 字符串必须 encode 转为字节,统一使用 utf-8;
hexdigest()获取可读十六进制字符串,开发最常用;- SHA 是单向哈希算法,不可逆,不要当作加密算法;
- 对外接口签名务必加盐,增加破解难度;
- 新项目优先 SHA256,淘汰 SHA1。