Python SHA-256哈希 — hashlib
直接在浏览器中使用免费的 SHA-256哈希生成器,无需安装。
在线试用 SHA-256哈希生成器 →我搭建的每条部署流水线,最终都需要验证文件校验和、对 Webhook 载荷签名,或为缓存键生成指纹。借助内置的 hashlib 模块,Python SHA-256 哈希可以处理所有这些场景——而且你已经自带了它。 hashlib.sha256() 在 CPython 上封装了 OpenSSL 的实现,速度快且开箱即用符合 FIPS 标准。 如需快速获得一次性哈希而无需编写任何代码, 在线 SHA-256 哈希生成器 可立即给出结果。本文所有示例均以 Python 3.9+ 为目标。
- ✓hashlib.sha256(data).hexdigest() 是对字节进行哈希的标准方式——属于标准库,底层由 OpenSSL 支持。
- ✓字符串必须先编码为字节:hashlib.sha256("text".encode("utf-8"))。
- ✓对文件计算校验和时,通过 .update() 分块输入——切勿一次性将大文件读入内存。
- ✓HMAC-SHA256 需要使用 hmac 模块:hmac.new(key, msg, hashlib.sha256)——SHA-256 本身不支持密钥。
什么是 SHA-256 哈希?
SHA-256(安全哈希算法,256 位)接受任意长度的输入,生成固定的 256 位(32 字节)摘要。相同输入始终产生相同输出,但输入中哪怕只改变一个比特,也会产生完全不同的哈希——这一特性称为雪崩效应。SHA-256 属于 SHA-2 家族,由 NIST 标准化,是 TLS 证书指纹、Git 提交 ID、比特币区块头以及文件完整性验证的核心算法。该算法采用 Merkle-Damgård 结构,经过 64 轮压缩产生 256 位输出。
deployment-v4.2.1
a1f7c3d8e9b2...27ae41e4649b (64 个十六进制字符)
上面的十六进制摘要是标准表示形式——64 个十六进制字符,无论你哈希的是单个字节还是整个磁盘镜像,长度始终相同。
hashlib.sha256() — 标准库方案
hashlib 模块随每个 Python 安装一起提供——无需 pip install。 向 hashlib.sha256() 传入 bytes 参数以创建哈希对象,然后通过 .hexdigest() (十六进制字符串)或 .digest() (原始字节)获取结果。函数名为小写: sha256, 而非 SHA256。
import hashlib # 直接对字节字符串哈希 digest = hashlib.sha256(b"deployment-v4.2.1").hexdigest() print(digest) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
使用 hashlib.sha256() 最常见的错误是传入 str 而非 bytes。 Python 字符串是 Unicode,而哈希函数处理原始字节。必须在哈希前调用 .encode("utf-8")。 几乎每个人第一次都会在这里踩坑。
import hashlib
# 字符串在哈希前必须编码为字节
config_key = "redis://cache.internal:6379/0"
digest = hashlib.sha256(config_key.encode("utf-8")).hexdigest()
print(digest)
# 7d3f8c2a1b9e4f5d6c8a7b3e2f1d9c4a5b8e7f6d3c2a1b9e4f5d6c8a7b3e2f1d.update() 方法允许增量输入数据。调用 h.update(a); h.update(b) 等同于 hashlib.sha256(a + b)。 这正是分块哈希文件、无需将全部内容加载到内存的方法。
import hashlib h = hashlib.sha256() h.update(b"request_id=req_7f3a91bc") h.update(b"×tamp=1741614120") h.update(b"&amount=4999") print(h.hexdigest()) # 等同于 hashlib.sha256(b"request_id=req_7f3a91bc×tamp=1741614120&amount=4999").hexdigest()
.digest() 返回原始 32 字节。 .hexdigest() 返回 64 字符十六进制字符串。 当需要将结果输入 HMAC、进行 Base64 编码或写入二进制协议时,使用 .digest()。 用于日志记录、数据库字段和校验和比对时,使用 .hexdigest()。HMAC-SHA256 — 使用 hmac 模块进行带密钥哈希
SHA-256 本身没有密钥的概念——任何人只要拿到相同的输入,就能计算出相同的哈希值。如果需要证明消息来自特定发送方(Webhook 验证、API 请求签名、令牌认证),就需要 HMAC。 hmac 模块是 Python 标准库的一部分,它将密钥嵌入哈希过程,只有持有密钥的人才能生成或验证相同的摘要。
import hmac
import hashlib
# Webhook 签名验证
secret_key = b"whsec_9f3a7b2e1d4c8a5b"
payload = b'{"event":"invoice.paid","invoice_id":"inv_8d2c","amount":14900}'
signature = hmac.new(secret_key, payload, hashlib.sha256).hexdigest()
print(signature)
# 64 字符十六进制 HMAC-SHA256 摘要验证传入的 HMAC 时,需要使用 hmac.compare_digest() 而非 == 运算符。等号运算符在第一个不匹配的字节处就会短路,攻击者可以通过测量响应时间逐字节猜出正确签名。 compare_digest() 无论不匹配发生在何处,始终以恒定时间运行。
import hmac
import hashlib
def verify_webhook(payload: bytes, received_sig: str, secret: bytes) -> bool:
"""使用恒定时间比较验证 Webhook 签名。"""
expected = hmac.new(secret, payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received_sig)
# 模拟 Stripe 风格的 Webhook 验证
incoming_payload = b'{"event":"payment.completed","amount":4999}'
incoming_signature = "a1b2c3d4e5f6..." # 来自 X-Signature 请求头
webhook_secret = b"whsec_9f3a7b2e1d4c"
if verify_webhook(incoming_payload, incoming_signature, webhook_secret):
print("签名有效——处理该事件")
else:
print("签名不匹配——拒绝请求")HMAC-SHA256 请求签名
API 请求签名遵循相同原理:从请求组成部分(方法、路径、时间戳、请求体哈希)构造规范字符串,并用密钥对其签名。AWS Signature V4、Stripe 和 GitHub Webhooks 都使用这一模式的变体。
import hmac
import hashlib
import time
def sign_request(method: str, path: str, body: bytes, secret: bytes) -> str:
"""为 API 请求创建 HMAC-SHA256 签名。"""
timestamp = str(int(time.time()))
body_hash = hashlib.sha256(body).hexdigest()
# 规范字符串:方法 + 路径 + 时间戳 + 请求体哈希
canonical = f"{method}\n{path}\n{timestamp}\n{body_hash}"
signature = hmac.new(secret, canonical.encode("utf-8"), hashlib.sha256).hexdigest()
return f"ts={timestamp},sig={signature}"
# 使用示例
api_secret = b"sk_live_9f3a7b2e1d4c8a5b6e7f"
request_body = b'{"customer_id":"cust_4f2a","plan":"enterprise"}'
auth_header = sign_request("POST", "/api/v2/subscriptions", request_body, api_secret)
print(f"Authorization: HMAC-SHA256 {auth_header}")
# Authorization: HMAC-SHA256 ts=1741614120,sig=7d3f8c2a...Base64 编码的 HMAC-SHA256
某些 API(AWS Signature V4、部分支付网关)期望 HMAC 结果以 Base64 编码字符串而非十六进制表示。区别在于:十六进制使用 64 个字符,而 Base64 对相同的 32 字节摘要只需 44 个字符。
import hmac
import hashlib
import base64
secret = b"webhook_secret_9f3a"
message = b"POST /api/v2/events 1741614120"
# 十六进制输出:64 个字符
hex_sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
print(f"Hex: {hex_sig}")
# Base64 输出:44 个字符(更短,HTTP 头部中常见)
raw_sig = hmac.new(secret, message, hashlib.sha256).digest()
b64_sig = base64.b64encode(raw_sig).decode("ascii")
print(f"Base64: {b64_sig}")对 datetime、UUID 及自定义对象进行哈希
SHA-256 处理原始字节,因此非字节类型——datetime、 UUID、dataclass、Pydantic 模型——必须先序列化为字节再进行哈希。没有自动转换;需要自行选择规范表示形式。 为确保跨系统的确定性哈希,始终使用显式编码和稳定的序列化格式(datetime 用 ISO 8601,UUID 用标准字符串形式,dict 用排序键 JSON)。
import hashlib
import uuid
from datetime import datetime, timezone
# datetime — 使用带显式 UTC 偏移量的 ISO 8601 以确保可移植性
event_time = datetime(2026, 3, 28, 12, 0, 0, tzinfo=timezone.utc)
time_hash = hashlib.sha256(event_time.isoformat().encode("utf-8")).hexdigest()
print(f"datetime 哈希:{time_hash[:16]}...")
# UUID — 对规范字符串形式进行哈希(小写,带连字符)
record_id = uuid.uuid4()
uuid_hash = hashlib.sha256(str(record_id).encode("utf-8")).hexdigest()
print(f"UUID 哈希:{uuid_hash[:16]}...")对于自定义对象,在哈希前将其序列化为规范字节表示。带排序键的 JSON 非常适合类字典对象:
import hashlib
import json
from dataclasses import dataclass, asdict
@dataclass
class Event:
id: str
type: str
amount: int
timestamp: str
def hash_event(event: Event) -> str:
"""使用排序键 JSON 对 dataclass 实例进行哈希,确保确定性。"""
canonical = json.dumps(asdict(event), sort_keys=True, separators=(",", ":"))
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
e = Event(id="evt_4f2a", type="payment.completed", amount=4999, timestamp="2026-03-28T12:00:00Z")
print(hash_event(e)) # 在不同运行和机器上结果稳定sort_keys=True)。Python 3.7+ 保留了字典插入顺序,但不同序列化路径可能产生不同顺序,导致相同数据产生不同哈希。SHA-256 文件校验和——验证下载和构建产物
计算文件的 SHA-256 校验和是该算法最常见的用途之一。你随处可见:Go 二进制文件的发布页面、Python wheel 文件、Docker 镜像清单、固件更新。关键在于分块读取文件,而非一次性加载——哈希一个 2 GB 的 ISO 镜像不应该因此消耗 2 GB 内存。
import hashlib
def sha256_checksum(filepath: str, chunk_size: int = 8192) -> str:
"""分块读取计算文件 SHA-256 哈希,节省内存。"""
h = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(chunk_size), b""):
h.update(chunk)
return h.hexdigest()
# 对发布产物进行哈希
checksum = sha256_checksum("/tmp/release-v4.2.1.tar.gz")
print(f"SHA-256: {checksum}")Python 3.11 新增了 hashlib.file_digest(), 它在内部处理分块读取,并在支持的平台上可能使用零拷贝优化。如果你使用 3.11 或更高版本,推荐使用它代替手动循环。
import hashlib
with open("/tmp/release-v4.2.1.tar.gz", "rb") as f:
digest = hashlib.file_digest(f, "sha256")
print(digest.hexdigest())对照已知校验和验证下载文件
import hashlib
import hmac as hmac_mod # 仅用于 compare_digest
def verify_checksum(filepath: str, expected_hex: str) -> bool:
"""使用恒定时间比较验证 SHA-256 校验和。"""
h = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
return hmac_mod.compare_digest(h.hexdigest(), expected_hex.lower())
# 验证发布产物
expected = "a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db"
if verify_checksum("/tmp/release-v4.2.1.tar.gz", expected):
print("校验和匹配——文件完整")
else:
print("校验和不匹配——文件可能已损坏或被篡改")hmac.compare_digest()。 恒定时间比较可防止基于时序的信息泄漏。 == 运算符在功能上可用,但不适合安全敏感场景。SHA-256 与 Base64 编码
某些协议期望 SHA-256 摘要以 Base64 字符串而非十六进制表示。 HTTP 头部如 Content-Digest 和 Integrity (浏览器的子资源完整性)使用 Base64,JWT 签名也使用 Base64url 编码。 关键是对原始 .digest() 字节进行 Base64 编码,而非对十六进制字符串编码。
import hashlib
import base64
data = b"integrity check payload"
# 正确:对原始字节进行 Base64 编码(32 字节 → 44 个 Base64 字符)
raw_digest = hashlib.sha256(data).digest()
b64_digest = base64.b64encode(raw_digest).decode("ascii")
print(f"sha256-{b64_digest}")
# sha256-<44 个字符>
# 错误:对十六进制字符串进行 Base64 编码(64 个 ASCII 字节 → 88 个 Base64 字符——体积翻倍)
hex_digest = hashlib.sha256(data).hexdigest()
wrong = base64.b64encode(hex_digest.encode()).decode()
print(f"错误长度:{len(wrong)} 个字符") # 88——API 不期望这个.digest(),而非 .hexdigest()。hashlib.sha256() 参考
SHA-256 哈希对象的构造函数及方法:
带密钥哈希所用 hmac.new() 的参数:
cryptography 库——另一种 SHA-256 API
cryptography 包通过其 hazmat 原语提供了另一种 SHA-256 API。当我只需要哈希时,很少会用到它——hashlib 更简单,且没有外部依赖。但如果你的项目已经依赖 cryptography 用于 TLS、X.509 或对称加密,使用其哈希 API 可以将所有内容集中在一个库下,并获得统一的错误处理。
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.backends import default_backend digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) digest.update(b"deployment-v4.2.1") result = digest.finalize() # 原始 32 字节 print(result.hex()) # 64 字符十六进制字符串 # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
cryptography 库需要 pip install cryptography。哈希对象是一次性使用的: 第二次调用 .finalize() 会引发 AlreadyFinalized 异常。如需分支哈希状态,请在调用 finalize 前使用 .copy()。对文件和 API 响应体进行哈希
有两种场景频繁出现:对磁盘上的文件进行哈希以验证发布产物,以及对 HTTP 响应体进行哈希以用作缓存键或验证 Webhook。
读取文件 → 计算 SHA-256 → 比较
import hashlib
import sys
def hash_file_safe(filepath: str) -> str | None:
"""带完整错误处理的文件哈希。"""
try:
h = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(16384), b""):
h.update(chunk)
return h.hexdigest()
except FileNotFoundError:
print(f"错误:未找到 {filepath}", file=sys.stderr)
return None
except PermissionError:
print(f"错误:无权读取 {filepath}", file=sys.stderr)
return None
result = hash_file_safe("/etc/nginx/nginx.conf")
if result:
print(f"SHA-256: {result}")HTTP 响应体 → 哈希用作缓存键
import hashlib
import urllib.request
import json
def fetch_and_hash(url: str) -> tuple[dict, str]:
"""从 API 获取 JSON 并返回数据及其 SHA-256 哈希。"""
try:
with urllib.request.urlopen(url, timeout=10) as resp:
body = resp.read()
content_hash = hashlib.sha256(body).hexdigest()
data = json.loads(body)
return data, content_hash
except urllib.error.URLError as exc:
raise ConnectionError(f"获取 {url} 失败:{exc}") from exc
# 基于响应内容的缓存键
data, digest = fetch_and_hash("https://api.exchange.internal/v2/rates")
print(f"响应哈希:{digest[:16]}...")
print(f"EUR/USD: {data.get('rates', {}).get('EUR', 'N/A')}")如需快速一次性验证, ToolDeck 的 SHA-256 生成器 完全在浏览器中运行——无需任何代码。
命令行 SHA-256 哈希
有时在处理故障或部署时,只需要在终端快速获取一个哈希值。Python 的 hashlib 模块没有内置的命令行子命令(不像 python3 -m json.tool), 但可以使用单行命令或系统工具。
# Python 单行命令 echo -n "deployment-v4.2.1" | python3 -c "import hashlib,sys; print(hashlib.sha256(sys.stdin.buffer.read()).hexdigest())" # macOS / BSD echo -n "deployment-v4.2.1" | shasum -a 256 # Linux(coreutils) echo -n "deployment-v4.2.1" | sha256sum # OpenSSL(跨平台) echo -n "deployment-v4.2.1" | openssl dgst -sha256
# 对发布压缩包进行哈希 sha256sum release-v4.2.1.tar.gz # 或 openssl dgst -sha256 release-v4.2.1.tar.gz # 对照已知校验和验证 echo "a8f5f167f44f4964e6c998dee827110c release-v4.2.1.tar.gz" | sha256sum -c - # release-v4.2.1.tar.gz: OK
echo -n(不带尾随换行符)。普通的 echo 会追加 \n,这会改变哈希值。这是 Python 与 Shell 之间哈希结果不同的首要原因。高性能替代方案——hashlib 配合 OpenSSL 与 pycryptodome
在 CPython 上, hashlib.sha256() 已经委托给 OpenSSL 的 C 实现,因此速度很快——在现代硬件上通常可达 500+ MB/s。
如果 SHA-256 哈希出现在你的性能分析报告中——例如在 CI 流水线中为数千个文件计算校验和,或在高吞吐量 API 网关中对每个请求体进行哈希——有两个选择:优化 hashlib 调用模式,或切换到 pycryptodome 以获得同时支持 SHA-3 和 BLAKE2 的统一加密 API:
pip install pycryptodome
from Crypto.Hash import SHA256 h = SHA256.new() h.update(b"deployment-v4.2.1") print(h.hexdigest()) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
对于高吞吐量并行文件哈希,更大的性能提升来自通过增大块大小和多线程来减少 Python 层面的开销:
import hashlib
import os
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def hash_file(path: Path) -> tuple[str, str]:
"""对单个文件进行哈希,返回(路径,十六进制摘要)。"""
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""): # 64 KB 块
h.update(chunk)
return str(path), h.hexdigest()
def hash_directory(directory: str, pattern: str = "*.tar.gz") -> dict[str, str]:
"""使用多线程并行哈希目录中所有匹配文件。"""
files = list(Path(directory).glob(pattern))
results = {}
with ThreadPoolExecutor(max_workers=os.cpu_count()) as pool:
for path, digest in pool.map(hash_file, files):
results[path] = digest
return results
# 并行哈希所有发布产物
checksums = hash_directory("/var/releases", "*.tar.gz")
for path, digest in checksums.items():
print(f"{digest} {path}")使用 64 KB 块而非 8 KB 块,Python 到 C 的调用次数减少了 8 倍。由于在 C 层哈希计算期间 GIL 会被释放,多线程在此处效果显著——瓶颈在磁盘 I/O,而非 CPU。
带语法高亮的终端输出
当你需要验证一批文件并希望以表格形式显示每个文件的通过/失败状态,而非让原始十六进制输出滚动而过时, rich 库非常有用。
pip install rich
import hashlib
from pathlib import Path
from rich.console import Console
from rich.table import Table
console = Console()
def hash_and_display(files: list[str], expected: dict[str, str]) -> None:
"""对文件进行哈希,并以彩色编码方式显示验证结果。"""
table = Table(title="SHA-256 验证")
table.add_column("文件", style="cyan")
table.add_column("SHA-256", style="dim", max_width=20)
table.add_column("状态")
for filepath in files:
h = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
digest = h.hexdigest()
name = Path(filepath).name
status = "[green]✓ OK[/green]" if expected.get(name) == digest else "[red]✗ 不匹配[/red]"
table.add_row(name, f"{digest[:16]}...", status)
console.print(table)
# 使用示例
expected_checksums = {
"api-gateway-v3.1.tar.gz": "a8f5f167f44f4964...",
"worker-v3.1.tar.gz": "7d3f8c2a1b9e4f5d...",
}
hash_and_display(
["/var/releases/api-gateway-v3.1.tar.gz", "/var/releases/worker-v3.1.tar.gz"],
expected_checksums,
)console.print(data, highlight=False) 去除高亮, 或通过 Console(file=open(...)) 重定向到文件。处理大文件
分块 .update() 模式可以以恒定内存用量处理任意大小的文件。对于非常大的文件(多 GB 的磁盘镜像、数据库备份),主要关注点从内存转移到用户反馈——以 500 MB/s 的速度哈希 10 GB 文件仍需 20 秒,这段时间的沉默会让人忐忑。
import hashlib
import os
def sha256_with_progress(filepath: str) -> str:
"""哈希大文件,并将进度输出到标准错误。"""
file_size = os.path.getsize(filepath)
h = hashlib.sha256()
bytes_read = 0
with open(filepath, "rb") as f:
while chunk := f.read(1 << 20): # 1 MB 块
h.update(chunk)
bytes_read += len(chunk)
pct = (bytes_read / file_size) * 100
print(f"\r 正在哈希:{pct:.1f}%({bytes_read >> 20} MB / {file_size >> 20} MB)",
end="", flush=True)
print() # 进度结束后换行
return h.hexdigest()
digest = sha256_with_progress("/mnt/backups/db-snapshot-2026-03.sql.gz")
print(f"SHA-256: {digest}")NDJSON / JSON Lines——对每条记录单独哈希
import hashlib
import json
def hash_ndjson_records(filepath: str) -> dict[str, str]:
"""对 NDJSON 文件中每条 JSON 记录进行哈希,用于去重。"""
seen = {}
with open(filepath, "r", encoding="utf-8") as f:
for line_num, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
try:
record = json.loads(line)
# 哈希前规范化:对键排序以确保确定性输出
canonical = json.dumps(record, sort_keys=True, separators=(",", ":"))
digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
if digest in seen:
print(f"第 {line_num} 行:与第 {seen[digest]} 行重复")
else:
seen[digest] = line_num
except json.JSONDecodeError:
print(f"第 {line_num} 行:无效的 JSON,已跳过")
print(f"已处理 {line_num} 行,{len(seen)} 条唯一记录")
return seen
hash_ndjson_records("telemetry-events-2026-03.ndjson")hashlib.sha256(data) 单次调用切换到分块 .update() 循环。低于该阈值时,使用 f.read() 读取整个文件也可以——内存用量大致等于文件大小。常见错误
问题: hashlib.sha256('text') 会引发 TypeError: Unicode-objects must be encoded before hashing。该函数需要 bytes,不接受 str。
解决方法: 先对字符串编码:hashlib.sha256('text'.encode('utf-8'))。对于硬编码值,也可使用 b'' 字面量。
import hashlib
digest = hashlib.sha256("deployment-v4.2.1").hexdigest()
# TypeError: Unicode-objects must be encoded before hashingimport hashlib
digest = hashlib.sha256("deployment-v4.2.1".encode("utf-8")).hexdigest()
# 正常运行——返回 64 字符十六进制字符串问题: == 运算符在第一个不匹配字节处短路。攻击者可通过测量响应时间逐字节猜出正确签名。
解决方法: 对所有安全敏感的比较使用 hmac.compare_digest()——无论不匹配发生在何处,它始终以恒定时间运行。
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if received_sig == expected_sig: # 存在时序攻击漏洞
process_webhook(body)received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if hmac.compare_digest(received_sig, expected_sig): # 恒定时间
process_webhook(body)问题: base64.b64encode(digest.hexdigest().encode()) 产生 88 字符字符串——是预期 44 字符的两倍。期望 Base64 编码 SHA-256 的 API 会拒绝它。
解决方法: Base64 编码前调用 .digest()(原始字节),而非 .hexdigest()(十六进制字符串)。
import hashlib, base64 hex_str = hashlib.sha256(data).hexdigest() b64 = base64.b64encode(hex_str.encode()) # 88 字符——错误!
import hashlib, base64 raw = hashlib.sha256(data).digest() b64 = base64.b64encode(raw) # 44 字符——正确
问题: hashlib.sha256(open('large.iso', 'rb').read()) 将整个文件加载到内存。一个 4 GB 的文件仅为了计算哈希就需要 4 GB 内存。
解决方法: 使用循环和 .update() 分块读取。无论文件大小,内存用量保持恒定。
import hashlib
# 将整个 4 GB 文件加载到内存
digest = hashlib.sha256(open("disk.iso", "rb").read()).hexdigest()import hashlib
h = hashlib.sha256()
with open("disk.iso", "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
digest = h.hexdigest() # 内存用量恒定hashlib vs hmac vs 其他方案——快速对比
对于简单哈希——校验和、缓存键、内容指纹——坚持使用 hashlib.sha256()。 一旦需要密钥(Webhook、API 签名、令牌认证),切换到 hmac.new()。 只有当项目已经使用 cryptography 库进行加密或 TLS 时,才考虑使用它——仅为哈希而引入一个 C 扩展依赖是多余的,因为 hashlib 本已底层使用 OpenSSL。
SHA-256 能被解密吗?——哈希与加密的区别
简短回答:不能。SHA-256 是单向函数。该算法被设计为不可逆——无法从 256 位摘要还原原始输入。这不是实现上的限制,而是哈希函数的数学特性。256 位输出空间极为庞大(2256 种可能值),且该函数在 64 轮压缩过程中丢弃了信息。
攻击者可以对弱输入(常用密码、短字符串)尝试暴力破解或字典攻击,但对于任何具有合理熵的输入——API 密钥、随机令牌、文件内容——以当前硬件逆向 SHA-256 在计算上是不可行的。如果需要可逆变换,请使用对称加密:
# 哈希——单向,无法还原原始值 import hashlib digest = hashlib.sha256(b"secret-config-value").hexdigest() # 无法从 digest 恢复 "secret-config-value" # 加密——双向,可用密钥解密 from cryptography.fernet import Fernet key = Fernet.generate_key() cipher = Fernet(key) encrypted = cipher.encrypt(b"secret-config-value") decrypted = cipher.decrypt(encrypted) print(decrypted) # b"secret-config-value" — 原始值已恢复
如需免安装、快速 生成 SHA-256 哈希, 在线工具完全在浏览器中运行。
如何在 Python 中检查字符串是否为有效的 SHA-256 哈希
有效的 SHA-256 十六进制摘要恰好是 64 个十六进制字符(0-9、a-f、A-F)。在处理不可信输入之前进行快速验证,可以避免令人困惑的下游错误。
import re
def is_sha256_hex(value: str) -> bool:
"""检查字符串是否符合 SHA-256 十六进制摘要格式。"""
return bool(re.fullmatch(r"[a-fA-F0-9]{64}", value))
# 测试用例
print(is_sha256_hex("e3b0c44298fc1c149afbf4c8996fb924"
"27ae41e4649b934ca495991b7852b855")) # True — 空字符串的 SHA-256
print(is_sha256_hex("e3b0c44298fc1c14")) # False — 太短
print(is_sha256_hex("zzzz" * 16)) # False — 无效的十六进制字符常见问题
如何在 Python 中对字符串进行 SHA-256 哈希?
将字符串编码为字节后调用 hashlib.sha256()。Python 字符串是 Unicode,而哈希函数处理原始字节,因此必须先调用 .encode("utf-8")。.hexdigest() 方法返回常见的 64 字符十六进制字符串。
import hashlib
api_key = "sk_live_9f3a7b2e1d4c"
digest = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
print(digest)
# e3b7c4a1f8d2...64 个十六进制字符可以将 SHA-256 哈希解密还原为原始文本吗?
不能。SHA-256 是单向函数——它将任意长度的输入映射为固定的 256 位输出,并在计算过程中丢弃了结构信息。数学上不存在逆运算。攻击者可以对弱输入(短密码、常用词)尝试暴力破解或彩虹表查找,但对于具有合理熵的任意输入,逆向 SHA-256 在计算上是不可行的。如果需要可逆变换,请使用加密(AES-GCM、Fernet)而非哈希。
.digest() 和 .hexdigest() 有什么区别?
.digest() 以 bytes 对象形式返回哈希的原始 32 字节。.hexdigest() 将相同数据编码为 64 个字符的小写十六进制字符串。当需要二进制输出时使用 .digest()——例如输入 HMAC、进行 Base64 编码或写入二进制协议。当需要用于日志记录、数据库存储或校验和比对的可读字符串时,使用 .hexdigest()。
import hashlib h = hashlib.sha256(b"deployment-v4.2.1") print(len(h.digest())) # 32(字节) print(len(h.hexdigest())) # 64(十六进制字符)
如何在 Python 中计算文件的 SHA-256 校验和?
以二进制模式打开文件,并通过 .update() 分块输入到哈希器中。在 Python 3.11+ 上,使用 hashlib.file_digest() 可获得更简洁的 API。切勿对大文件调用 f.read()——那会将整个文件加载到内存中。
import hashlib
def sha256_file(path: str) -> str:
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
return h.hexdigest()
print(sha256_file("release-v4.2.1.tar.gz"))如何在 Python 中创建 HMAC-SHA256 签名?
使用 hmac 模块,以 hashlib.sha256 作为 digestmod。将密钥和消息以 bytes 形式传入。结果是一个带密钥的哈希,同时证明完整性和真实性——接收方需要使用相同的密钥进行验证。
import hmac
import hashlib
secret = b"webhook_secret_9f3a"
payload = b'{"event":"payment.completed","amount":4999}'
signature = hmac.new(secret, payload, hashlib.sha256).hexdigest()
print(signature) # 64 字符十六进制 HMAC如何验证一个字符串是否为有效的 SHA-256 十六进制摘要?
SHA-256 十六进制摘要恰好是 64 个十六进制字符。使用正则表达式或简单的长度加字符检查即可。正则表达式方式最为直观。
import re
def is_sha256(s: str) -> bool:
return bool(re.fullmatch(r"[a-fA-F0-9]{64}", s))
print(is_sha256("e3b0c44298fc1c149afbf4c8996fb924"
"27ae41e4649b934ca495991b7852b855")) # True
print(is_sha256("not-a-hash")) # False相关工具
Dmitri is a DevOps engineer who relies on Python as his primary scripting and automation language. He builds internal tooling, CI/CD pipelines, and infrastructure automation scripts that run in production across distributed teams. He writes about the Python standard library, subprocess management, file processing, encoding utilities, and the practical shell-adjacent Python that DevOps engineers use every day.
Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.