Băm SHA-256 trong Python — Hướng dẫn hashlib
Sử dụng Trình tạo Hash SHA-256 miễn phí trực tiếp trên trình duyệt — không cần cài đặt.
Dùng thử Trình tạo Hash SHA-256 trực tuyến →Mọi pipeline triển khai tôi từng xây dựng đều đến lúc cần xác minh checksum tệp, ký payload webhook, hoặc tạo fingerprint cho cache key. Băm SHA-256 trong Python với module tích hợp sẵn hashlib xử lý tất cả những trường hợp đó — và bạn đã có sẵn nó sau khi cài Python. hashlib.sha256() bao bọc triển khai OpenSSL trên CPython, vì vậy nó nhanh và tuân thủ FIPS ngay từ đầu. Để tính hash nhanh mà không cần viết code, công cụ tạo hash SHA-256 trực tuyến cho kết quả ngay lập tức. Tất cả ví dụ đều dành cho Python 3.9+.
- ✓hashlib.sha256(data).hexdigest() là cách chuẩn để băm bytes — thuộc stdlib, được OpenSSL hỗ trợ.
- ✓Chuỗi phải được mã hóa thành bytes trước: hashlib.sha256("text".encode("utf-8")).
- ✓Với checksum tệp, đưa dữ liệu theo từng phần qua .update() — không bao giờ đọc toàn bộ tệp lớn vào bộ nhớ cùng lúc.
- ✓HMAC-SHA256 yêu cầu module hmac: hmac.new(key, msg, hashlib.sha256) — SHA-256 đơn thuần không có khóa.
SHA-256 là gì?
SHA-256 (Secure Hash Algorithm, 256-bit) nhận đầu vào có độ dài tùy ý và tạo ra digest cố định 256-bit (32 byte). Cùng một đầu vào luôn cho cùng đầu ra, nhưng chỉ cần thay đổi một bit trong đầu vào cũng tạo ra hash hoàn toàn khác — thuộc tính này gọi là hiệu ứng thác lũ. SHA-256 thuộc họ SHA-2, được NIST chuẩn hóa, và là nền tảng của fingerprint chứng chỉ TLS, ID commit Git, header block Bitcoin và xác minh tính toàn vẹn tệp. Thuật toán sử dụng cấu trúc Merkle-Damgård với 64 vòng nén để tạo ra đầu ra 256-bit.
deployment-v4.2.1
a1f7c3d8e9b2...27ae41e4649b (64 ký tự hex)
Digest hex ở trên là biểu diễn chuẩn — 64 ký tự thập lục phân, luôn có cùng độ dài bất kể bạn băm một byte hay toàn bộ ảnh đĩa.
hashlib.sha256() — Cách tiếp cận với thư viện chuẩn
Module hashlib đi kèm với mọi bản cài đặt Python — không cần pip install. Gọi hashlib.sha256() với đối số bytes để tạo đối tượng hash, sau đó lấy kết quả bằng .hexdigest() (chuỗi hex) hoặc .digest() (bytes thô). Tên hàm viết thường: sha256, không phải SHA256.
import hashlib # Băm trực tiếp một chuỗi byte digest = hashlib.sha256(b"deployment-v4.2.1").hexdigest() print(digest) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
Lỗi phổ biến nhất với hashlib.sha256() là truyền str thay vì bytes. Chuỗi Python là Unicode, còn hàm băm hoạt động trên bytes thô. Bạn phải gọi .encode("utf-8") trước khi băm. Hầu như ai cũng mắc lỗi này lần đầu.
import hashlib
# Chuỗi phải được mã hóa thành bytes trước khi băm
config_key = "redis://cache.internal:6379/0"
digest = hashlib.sha256(config_key.encode("utf-8")).hexdigest()
print(digest)
# 7d3f8c2a1b9e4f5d6c8a7b3e2f1d9c4a5b8e7f6d3c2a1b9e4f5d6c8a7b3e2f1dPhương thức .update() cho phép bạn đưa dữ liệu theo từng phần. Gọi h.update(a); h.update(b) tương đương với hashlib.sha256(a + b). Đây là cách băm tệp theo từng phần mà không cần tải toàn bộ nội dung vào bộ nhớ.
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()) # Tương đương hashlib.sha256(b"request_id=req_7f3a91bc×tamp=1741614120&amount=4999").hexdigest()
.digest() trả về 32 bytes thô. .hexdigest() trả về chuỗi hex 64 ký tự. Dùng .digest() khi đưa kết quả vào HMAC, mã hóa Base64, hoặc giao thức nhị phân. Dùng .hexdigest() cho việc ghi log, cột database và so sánh checksum.HMAC-SHA256 — Băm có khóa với module hmac
SHA-256 đơn thuần không có khái niệm khóa bí mật — bất kỳ ai có cùng đầu vào đều có thể tính ra cùng hash. Nếu bạn cần chứng minh rằng thông điệp đến từ một người gửi cụ thể (xác minh webhook, ký yêu cầu API, xác thực token), bạn cần HMAC. Module hmac là một phần của thư viện chuẩn Python và đưa khóa vào quá trình băm để chỉ người có khóa mới có thể tạo hoặc xác minh cùng digest.
import hmac
import hashlib
# Xác minh chữ ký 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)
# Digest HMAC-SHA256 hex 64 ký tựXác minh HMAC đến cần dùng hmac.compare_digest() thay vì toán tử ==. Toán tử bằng dễ bị tấn công timing — nó dừng sớm ở byte không khớp đầu tiên, và kẻ tấn công có thể đo thời gian phản hồi để đoán từng byte của chữ ký đúng. compare_digest() chạy trong thời gian cố định bất kể vị trí không khớp.
import hmac
import hashlib
def verify_webhook(payload: bytes, received_sig: str, secret: bytes) -> bool:
"""Xác minh chữ ký webhook bằng so sánh thời gian cố định."""
expected = hmac.new(secret, payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received_sig)
# Mô phỏng xác minh webhook kiểu Stripe
incoming_payload = b'{"event":"payment.completed","amount":4999}'
incoming_signature = "a1b2c3d4e5f6..." # từ header X-Signature
webhook_secret = b"whsec_9f3a7b2e1d4c"
if verify_webhook(incoming_payload, incoming_signature, webhook_secret):
print("Chữ ký hợp lệ — xử lý sự kiện")
else:
print("Chữ ký không khớp — từ chối yêu cầu")Ký yêu cầu API với HMAC-SHA256
Ký yêu cầu API theo cùng nguyên tắc: xây dựng chuỗi chuẩn hóa từ các thành phần của yêu cầu (phương thức, đường dẫn, timestamp, hash body) và ký bằng khóa bí mật. AWS Signature V4, Stripe và GitHub webhooks đều dùng các biến thể của mẫu này.
import hmac
import hashlib
import time
def sign_request(method: str, path: str, body: bytes, secret: bytes) -> str:
"""Tạo chữ ký HMAC-SHA256 cho một yêu cầu API."""
timestamp = str(int(time.time()))
body_hash = hashlib.sha256(body).hexdigest()
# Chuỗi chuẩn hóa: method + path + timestamp + hash body
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}"
# Sử dụng
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...HMAC-SHA256 mã hóa Base64
Một số API (AWS Signature V4, các cổng thanh toán) mong đợi kết quả HMAC dưới dạng chuỗi Base64 thay vì hex. Sự khác biệt: hex dùng 64 ký tự, Base64 dùng 44 ký tự cho cùng digest 32 byte.
import hmac
import hashlib
import base64
secret = b"webhook_secret_9f3a"
message = b"POST /api/v2/events 1741614120"
# Đầu ra hex: 64 ký tự
hex_sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
print(f"Hex: {hex_sig}")
# Đầu ra Base64: 44 ký tự (ngắn hơn, phổ biến trong HTTP header)
raw_sig = hmac.new(secret, message, hashlib.sha256).digest()
b64_sig = base64.b64encode(raw_sig).decode("ascii")
print(f"Base64: {b64_sig}")Băm datetime, UUID và đối tượng tùy chỉnh
SHA-256 hoạt động trên bytes thô, vì vậy các kiểu không phải bytes — datetime, UUID, dataclass, mô hình Pydantic — phải được chuyển đổi thành bytes trước khi băm. Không có chuyển đổi tự động; bạn chọn biểu diễn chuẩn hóa. Để băm xác định trên nhiều hệ thống, luôn dùng encoding tường minh và định dạng tuần tự hóa ổn định (ISO 8601 cho datetime, dạng chuỗi chuẩn cho UUID, JSON khóa được sắp xếp cho dict).
import hashlib
import uuid
from datetime import datetime, timezone
# datetime — dùng ISO 8601 với offset UTC tường minh để đảm bảo tính di động
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"hash datetime: {time_hash[:16]}...")
# UUID — băm dạng chuỗi chuẩn (chữ thường, có dấu gạch ngang)
record_id = uuid.uuid4()
uuid_hash = hashlib.sha256(str(record_id).encode("utf-8")).hexdigest()
print(f"hash UUID: {uuid_hash[:16]}...")Với đối tượng tùy chỉnh, hãy chuyển đổi sang biểu diễn bytes chuẩn hóa trước khi băm. JSON với khóa được sắp xếp phù hợp cho các đối tượng dạng dict:
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:
"""Băm một instance dataclass dùng JSON khóa được sắp xếp để đảm bảo tính xác định."""
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)) # ổn định qua các lần chạy và máy tínhsort_keys=True) khi băm đối tượng được tuần tự hóa JSON. Thứ tự chèn dict được giữ nguyên trong Python 3.7+ nhưng có thể khác nhau qua các đường dẫn tuần tự hóa, tạo ra hash khác nhau cho dữ liệu giống nhau.Checksum SHA-256 của tệp — Xác minh tải xuống và artifact
Tính checksum SHA-256 của tệp là một trong những cách dùng phổ biến nhất của thuật toán. Bạn thấy nó ở khắp nơi: trang phát hành nhị phân Go, tệp wheel Python, manifest ảnh Docker, cập nhật firmware. Điều quan trọng là đọc tệp theo từng phần thay vì tải tất cả cùng lúc — một ảnh ISO 2 GB không cần 2 GB RAM chỉ để băm.
import hashlib
def sha256_checksum(filepath: str, chunk_size: int = 8192) -> str:
"""Tính hash SHA-256 của tệp, đọc theo từng phần để tiết kiệm bộ nhớ."""
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()
# Băm artifact phát hành
checksum = sha256_checksum("/tmp/release-v4.2.1.tar.gz")
print(f"SHA-256: {checksum}")Python 3.11 bổ sung hashlib.file_digest() thực hiện việc đọc theo từng phần nội bộ và có thể dùng tối ưu hóa zero-copy trên các nền tảng được hỗ trợ. Nếu bạn đang dùng 3.11 trở lên, hãy ưu tiên nó thay vì vòng lặp thủ công.
import hashlib
with open("/tmp/release-v4.2.1.tar.gz", "rb") as f:
digest = hashlib.file_digest(f, "sha256")
print(digest.hexdigest())Xác minh tệp tải xuống với checksum đã biết
import hashlib
import hmac as hmac_mod # chỉ dùng compare_digest
def verify_checksum(filepath: str, expected_hex: str) -> bool:
"""Xác minh checksum SHA-256 bằng so sánh thời gian cố định."""
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())
# Xác minh artifact phát hành
expected = "a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db"
if verify_checksum("/tmp/release-v4.2.1.tar.gz", expected):
print("Checksum khớp — tệp còn nguyên vẹn")
else:
print("Checksum không khớp — tệp có thể bị hỏng hoặc bị giả mạo")hmac.compare_digest() để so sánh checksum, ngay cả khi không có khóa bí mật. So sánh thời gian cố định ngăn rò rỉ thông tin dựa trên timing. Toán tử == hoạt động về mặt chức năng nhưng không an toàn trong các ngữ cảnh nhạy cảm về bảo mật.SHA-256 với mã hóa Base64
Một số giao thức mong đợi digest SHA-256 dưới dạng chuỗi Base64 thay vì hex. Các HTTP header như Content-Digest và Integrity (Subresource Integrity trong trình duyệt) dùng Base64, và chữ ký JWT được mã hóa Base64url. Bí quyết là mã hóa Base64 cho bytes thô từ .digest(), không phải chuỗi hex.
import hashlib
import base64
data = b"integrity check payload"
# Đúng: Base64 của bytes thô (32 bytes → 44 ký tự Base64)
raw_digest = hashlib.sha256(data).digest()
b64_digest = base64.b64encode(raw_digest).decode("ascii")
print(f"sha256-{b64_digest}")
# sha256-<44 ký tự>
# Sai: Base64 của chuỗi hex (64 byte ASCII → 88 ký tự Base64 — gấp đôi kích thước)
hex_digest = hashlib.sha256(data).hexdigest()
wrong = base64.b64encode(hex_digest.encode()).decode()
print(f"Độ dài sai: {len(wrong)} ký tự") # 88 — không phải những gì API mong đợi.digest(), không phải .hexdigest(), trước khi mã hóa Base64.Tham chiếu hashlib.sha256()
Constructor và các phương thức trên đối tượng hash SHA-256:
Tham số hmac.new() cho băm có khóa:
Thư viện cryptography — API SHA-256 thay thế
Gói cryptography cung cấp API khác cho SHA-256 thông qua các nguyên thủy hazmat của nó. Tôi hiếm khi dùng nó khi chỉ cần băm — hashlib đơn giản hơn và không có phụ thuộc bên ngoài. Nhưng nếu dự án của bạn đã phụ thuộc vào cryptography cho TLS, X.509, hoặc mã hóa đối xứng, việc dùng API hash của nó giữ mọi thứ trong một thư viện và cho bạn xử lý lỗi nhất quán.
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 bytes thô print(result.hex()) # chuỗi hex 64 ký tự # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
cryptography yêu cầu pip install cryptography. Đối tượng hash chỉ dùng được một lần: gọi .finalize() lần thứ hai sẽ ném AlreadyFinalized. Dùng .copy() trước khi finalize nếu bạn cần phân nhánh trạng thái hash.Băm dữ liệu từ tệp và phản hồi API
Hai tình huống xuất hiện thường xuyên: băm tệp trên đĩa để xác minh artifact phát hành, và băm nội dung phản hồi HTTP để dùng làm cache key hoặc xác minh webhook.
Đọc tệp → Tính SHA-256 → So sánh
import hashlib
import sys
def hash_file_safe(filepath: str) -> str | None:
"""Băm tệp với xử lý lỗi đầy đủ."""
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"Lỗi: không tìm thấy {filepath}", file=sys.stderr)
return None
except PermissionError:
print(f"Lỗi: không có quyền đọc {filepath}", file=sys.stderr)
return None
result = hash_file_safe("/etc/nginx/nginx.conf")
if result:
print(f"SHA-256: {result}")Phản hồi HTTP → Băm body làm Cache Key
import hashlib
import urllib.request
import json
def fetch_and_hash(url: str) -> tuple[dict, str]:
"""Lấy JSON từ API và trả về cả dữ liệu lẫn hash SHA-256 của nó."""
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"Không thể lấy {url}: {exc}") from exc
# Cache key dựa trên nội dung phản hồi
data, digest = fetch_and_hash("https://api.exchange.internal/v2/rates")
print(f"Hash phản hồi: {digest[:16]}...")
print(f"EUR/USD: {data.get('rates', {}).get('EUR', 'N/A')}")Để kiểm tra nhanh không cần viết code, công cụ SHA-256 của ToolDeck chạy hoàn toàn trên trình duyệt của bạn.
Băm SHA-256 trên dòng lệnh
Đôi khi bạn chỉ cần hash nhanh trong terminal trong lúc xử lý sự cố hoặc triển khai. Module hashlib của Python không có lệnh con CLI tích hợp (không giống như python3 -m json.tool), nhưng bạn có thể dùng one-liner hoặc công cụ hệ thống.
# Python one-liner 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 (đa nền tảng) echo -n "deployment-v4.2.1" | openssl dgst -sha256
# Băm tarball phát hành sha256sum release-v4.2.1.tar.gz # hoặc openssl dgst -sha256 release-v4.2.1.tar.gz # Xác minh với checksum đã biết echo "a8f5f167f44f4964e6c998dee827110c release-v4.2.1.tar.gz" | sha256sum -c - # release-v4.2.1.tar.gz: OK
echo -n (không có ký tự xuống dòng ở cuối) khi băm chuỗi trên dòng lệnh. echo thông thường thêm \n, làm thay đổi hash. Đây là lý do số một khiến người ta nhận được hash khác nhau giữa Python và shell.Phương án hiệu suất cao — hashlib với OpenSSL và pycryptodome
Trên CPython, hashlib.sha256() đã ủy quyền cho triển khai C của OpenSSL, vì vậy nó nhanh — thường đạt 500+ MB/s trên phần cứng hiện đại.
Nếu băm SHA-256 xuất hiện trong profiler — chẳng hạn bạn đang tính checksum cho hàng nghìn tệp trong CI pipeline hoặc băm mọi body yêu cầu trong API gateway thông lượng cao — có hai lựa chọn: tối ưu hóa cách gọi hashlib, hoặc chuyển sang pycryptodome cho API crypto thống nhất cũng hỗ trợ SHA-3 và BLAKE2:
pip install pycryptodome
from Crypto.Hash import SHA256 h = SHA256.new() h.update(b"deployment-v4.2.1") print(h.hexdigest()) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
Với băm tệp song song thông lượng cao, lợi ích lớn hơn đến từ việc giảm chi phí Python thông qua kích thước chunk lớn hơn và luồng xử lý:
import hashlib
import os
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def hash_file(path: Path) -> tuple[str, str]:
"""Băm một tệp và trả về (đường dẫn, hex digest)."""
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""): # chunk 64 KB
h.update(chunk)
return str(path), h.hexdigest()
def hash_directory(directory: str, pattern: str = "*.tar.gz") -> dict[str, str]:
"""Băm tất cả tệp phù hợp song song bằng luồng."""
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
# Băm tất cả artifact phát hành song song
checksums = hash_directory("/var/releases", "*.tar.gz")
for path, digest in checksums.items():
print(f"{digest} {path}")Dùng chunk 64 KB thay vì 8 KB giảm số lần gọi từ Python xuống C đi 8 lần. Luồng hoạt động tốt ở đây vì GIL được giải phóng trong quá trình băm ở cấp C — nút thắt cổ chai là I/O đĩa, không phải CPU.
Đầu ra terminal với tô sáng cú pháp
Thư viện rich hữu ích khi bạn cần xác minh một loạt tệp và muốn bảng hiển thị trạng thái đạt/không đạt cho từng tệp thay vì cuộn qua hex thô.
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:
"""Băm tệp và hiển thị kết quả với xác minh màu sắc."""
table = Table(title="Xác minh SHA-256")
table.add_column("Tệp", style="cyan")
table.add_column("SHA-256", style="dim", max_width=20)
table.add_column("Trạng thái")
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]✗ KHÔNG KHỚP[/red]"
table.add_row(name, f"{digest[:16]}...", status)
console.print(table)
# Sử dụng
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) hoặc chuyển hướng sang tệp với Console(file=open(...)).Làm việc với tệp lớn
Mẫu .update() theo từng phần xử lý tệp có kích thước bất kỳ với bộ nhớ sử dụng cố định. Với tệp rất lớn (ảnh đĩa nhiều GB, bản sao lưu database), mối quan tâm chính chuyển từ bộ nhớ sang phản hồi cho người dùng — băm 10 GB ở 500 MB/s vẫn mất 20 giây, và sự im lặng trong thời gian đó khiến người ta lo lắng.
import hashlib
import os
def sha256_with_progress(filepath: str) -> str:
"""Băm tệp lớn với báo cáo tiến độ ra stderr."""
file_size = os.path.getsize(filepath)
h = hashlib.sha256()
bytes_read = 0
with open(filepath, "rb") as f:
while chunk := f.read(1 << 20): # chunk 1 MB
h.update(chunk)
bytes_read += len(chunk)
pct = (bytes_read / file_size) * 100
print(f"\r Đang băm: {pct:.1f}% ({bytes_read >> 20} MB / {file_size >> 20} MB)",
end="", flush=True)
print() # xuống dòng sau tiến độ
return h.hexdigest()
digest = sha256_with_progress("/mnt/backups/db-snapshot-2026-03.sql.gz")
print(f"SHA-256: {digest}")NDJSON / JSON Lines — Băm từng bản ghi riêng biệt
import hashlib
import json
def hash_ndjson_records(filepath: str) -> dict[str, str]:
"""Băm từng bản ghi JSON trong tệp NDJSON để loại bỏ trùng lặp."""
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)
# Chuẩn hóa trước khi băm: sắp xếp khóa để đảm bảo đầu ra xác định
canonical = json.dumps(record, sort_keys=True, separators=(",", ":"))
digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
if digest in seen:
print(f"Dòng {line_num}: trùng lặp với dòng {seen[digest]}")
else:
seen[digest] = line_num
except json.JSONDecodeError:
print(f"Dòng {line_num}: JSON không hợp lệ, bỏ qua")
print(f"Đã xử lý {line_num} dòng, {len(seen)} bản ghi duy nhất")
return seen
hash_ndjson_records("telemetry-events-2026-03.ndjson")hashlib.sha256(data) sang vòng lặp .update() theo từng phần khi tệp vượt quá 50–100 MB. Dưới ngưỡng đó, đọc toàn bộ tệp với f.read() vẫn ổn — bộ nhớ sử dụng sẽ xấp xỉ bằng kích thước tệp.Các lỗi thường gặp
Vấn đề: hashlib.sha256('text') ném TypeError: Unicode-objects must be encoded before hashing. Hàm yêu cầu bytes, không phải str.
Giải pháp: Mã hóa chuỗi trước: hashlib.sha256('text'.encode('utf-8')). Hoặc dùng literal b'' cho giá trị cố định.
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()
# Hoạt động — trả về chuỗi hex 64 ký tựVấn đề: Toán tử == dừng sớm ở byte không khớp đầu tiên. Kẻ tấn công có thể đo thời gian phản hồi để đoán từng byte của chữ ký đúng.
Giải pháp: Dùng hmac.compare_digest() cho mọi so sánh nhạy cảm về bảo mật — nó chạy trong thời gian cố định bất kể vị trí không khớp.
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if received_sig == expected_sig: # dễ bị tấn công timing
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): # thời gian cố định
process_webhook(body)Vấn đề: base64.b64encode(digest.hexdigest().encode()) tạo ra chuỗi 88 ký tự — gấp đôi so với 44 ký tự mong đợi. API mong đợi SHA-256 mã hóa Base64 sẽ từ chối nó.
Giải pháp: Gọi .digest() (bytes thô) trước khi mã hóa Base64, không phải .hexdigest() (chuỗi hex).
import hashlib, base64 hex_str = hashlib.sha256(data).hexdigest() b64 = base64.b64encode(hex_str.encode()) # 88 ký tự — sai!
import hashlib, base64 raw = hashlib.sha256(data).digest() b64 = base64.b64encode(raw) # 44 ký tự — đúng
Vấn đề: hashlib.sha256(open('large.iso', 'rb').read()) tải toàn bộ tệp vào bộ nhớ. Một tệp 4 GB cần 4 GB RAM chỉ để tính hash.
Giải pháp: Đọc theo từng phần với vòng lặp và .update(). Bộ nhớ sử dụng giữ cố định bất kể kích thước tệp.
import hashlib
# Tải toàn bộ tệp 4 GB vào bộ nhớ
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() # bộ nhớ sử dụng cố địnhhashlib vs hmac vs Các lựa chọn thay thế — So sánh nhanh
Với băm đơn giản — checksum, cache key, fingerprint nội dung — hãy dùng hashlib.sha256(). Chuyển sang hmac.new() khi bạn cần khóa bí mật (webhook, chữ ký API, xác thực token). Dùng thư viện cryptography chỉ khi dự án đã dùng nó cho mã hóa hoặc TLS — thêm phụ thuộc C extension chỉ để băm là quá mức cần thiết khi hashlib đã được OpenSSL hỗ trợ.
Có thể giải mã SHA-256 không? — Băm vs Mã hóa
Câu trả lời ngắn: không. SHA-256 là hàm một chiều. Thuật toán được thiết kế không thể đảo ngược — bạn không thể tái tạo đầu vào gốc từ digest 256-bit. Đây không phải giới hạn của triển khai; đây là tính chất toán học của hàm băm. Không gian đầu ra 256-bit có kích thước khổng lồ (2256 giá trị có thể), và hàm loại bỏ thông tin trong 64 vòng nén của nó.
Kẻ tấn công có thể thử brute-force hoặc tấn công từ điển với đầu vào yếu (mật khẩu thông thường, chuỗi ngắn), nhưng với bất kỳ đầu vào nào có entropy tốt — API key, token ngẫu nhiên, nội dung tệp — việc đảo ngược SHA-256 là không khả thi với phần cứng hiện tại. Nếu bạn cần chuyển đổi có thể đảo ngược, hãy dùng mã hóa đối xứng:
# Băm — một chiều, không thể khôi phục gốc import hashlib digest = hashlib.sha256(b"secret-config-value").hexdigest() # Không có cách nào lấy lại "secret-config-value" từ digest # Mã hóa — hai chiều, có thể giải mã với khóa 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" — khôi phục được bản gốc
Để nhanh chóng tạo hash SHA-256 mà không cần cài đặt, công cụ trực tuyến chạy hoàn toàn trong trình duyệt của bạn.
Cách kiểm tra xem chuỗi có phải là hash SHA-256 hợp lệ trong Python không
Một digest hex SHA-256 hợp lệ có đúng 64 ký tự thập lục phân (0-9, a-f, A-F). Xác thực nhanh trước khi xử lý đầu vào không tin cậy giúp tránh các lỗi khó hiểu về sau.
import re
def is_sha256_hex(value: str) -> bool:
"""Kiểm tra xem chuỗi có khớp định dạng digest hex SHA-256 không."""
return bool(re.fullmatch(r"[a-fA-F0-9]{64}", value))
# Các trường hợp kiểm tra
print(is_sha256_hex("e3b0c44298fc1c149afbf4c8996fb924"
"27ae41e4649b934ca495991b7852b855")) # True — SHA-256 của chuỗi rỗng
print(is_sha256_hex("e3b0c44298fc1c14")) # False — quá ngắn
print(is_sha256_hex("zzzz" * 16)) # False — ký tự hex không hợp lệCâu hỏi thường gặp
Làm thế nào để băm một chuỗi bằng SHA-256 trong Python?
Gọi hashlib.sha256() với chuỗi đã được mã hóa thành bytes. Chuỗi trong Python là Unicode, còn hàm băm hoạt động trên bytes thô, vì vậy bạn phải gọi .encode("utf-8") trước. Phương thức .hexdigest() trả về chuỗi hex 64 ký tự quen thuộc.
import hashlib
api_key = "sk_live_9f3a7b2e1d4c"
digest = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
print(digest)
# e3b7c4a1f8d2...64 ký tự hexCó thể giải mã hash SHA-256 về văn bản gốc không?
Không. SHA-256 là hàm một chiều — nó ánh xạ đầu vào có độ dài tùy ý thành đầu ra 256-bit cố định và loại bỏ cấu trúc trong quá trình đó. Không có phép nghịch đảo toán học nào. Kẻ tấn công có thể thử brute-force hoặc tra bảng rainbow với đầu vào yếu (mật khẩu ngắn, từ thông dụng), nhưng với bất kỳ đầu vào nào có entropy hợp lý, việc đảo ngược SHA-256 là không khả thi về mặt tính toán. Nếu bạn cần chuyển đổi có thể đảo ngược, hãy dùng mã hóa (AES-GCM, Fernet) thay vì băm.
Sự khác biệt giữa .digest() và .hexdigest() là gì?
.digest() trả về 32 bytes thô của hash dưới dạng đối tượng bytes. .hexdigest() trả về cùng dữ liệu đó được mã hóa thành chuỗi thập lục phân 64 ký tự viết thường. Dùng .digest() khi cần đầu ra nhị phân — đưa vào HMAC, mã hóa Base64, hoặc ghi vào giao thức nhị phân. Dùng .hexdigest() khi cần chuỗi có thể đọc được cho việc ghi log, lưu trữ database, hoặc so sánh checksum.
import hashlib h = hashlib.sha256(b"deployment-v4.2.1") print(len(h.digest())) # 32 (bytes) print(len(h.hexdigest())) # 64 (ký tự hex)
Làm thế nào để tính checksum SHA-256 của một tệp trong Python?
Mở tệp ở chế độ nhị phân và đưa vào hasher theo từng phần với .update(). Trên Python 3.11+, dùng hashlib.file_digest() để có API đơn giản hơn. Không bao giờ gọi f.read() với tệp lớn — điều đó tải toàn bộ tệp vào bộ nhớ.
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"))Làm thế nào để tạo chữ ký HMAC-SHA256 trong Python?
Dùng module hmac với hashlib.sha256 làm digestmod. Truyền khóa bí mật và thông điệp dưới dạng bytes. Kết quả là hash có khóa chứng minh cả tính toàn vẹn lẫn tính xác thực — bên nhận cần cùng khóa để xác minh.
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) # HMAC hex 64 ký tựLàm thế nào để kiểm tra xem một chuỗi có phải là digest SHA-256 hex hợp lệ không?
Một digest hex SHA-256 có đúng 64 ký tự thập lục phân. Dùng regex hoặc kiểm tra độ dài và ký tự đơn giản. Cách dùng regex là dễ đọc nhất.
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")) # FalseCông cụ liên quan
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.