SHA-256 хешування Python — hashlib та приклади коду
Використовуйте безкоштовний SHA-256 Hash Generator прямо в браузері — без встановлення.
Спробувати SHA-256 Hash Generator онлайн →Кожен конвеєр розгортання, який мені доводилося будувати, врешті-решт потребував перевірки контрольної суми файлу, підпису вебхук-запиту або визначення ключа кешу. SHA-256 хешування в Python за допомогою вбудованого модуля hashlib вирішує всі ці завдання — і він уже встановлений. hashlib.sha256() використовує реалізацію OpenSSL у CPython, тому він швидкий та сумісний з FIPS без додаткового налаштування. Для швидкого разового хешу без написання коду скористайтесь онлайн-генератором SHA-256 хешів — результат з'явиться миттєво. Усі приклади розраховані на Python 3.9+.
- ✓hashlib.sha256(data).hexdigest() — стандартний спосіб хешування байтів: входить до stdlib, реалізований через OpenSSL.
- ✓Рядки необхідно спочатку закодувати у байти: hashlib.sha256("text".encode("utf-8")).
- ✓Для контрольних сум файлів передавайте дані порціями через .update() — ніколи не зчитуйте великий файл цілком у пам'ять.
- ✓HMAC-SHA256 потребує модуля hmac: hmac.new(key, msg, hashlib.sha256) — SHA-256 сам по собі не підтримує ключ.
Що таке SHA-256 хешування?
SHA-256 (Secure Hash Algorithm, 256-бітний) приймає вхідні дані довільної довжини та виробляє фіксований 256-бітний (32-байтний) дайджест. Однакові вхідні дані завжди дають однаковий результат, але навіть зміна одного біта у вхідних даних призводить до повністю іншого хешу — ця властивість називається лавинним ефектом. SHA-256 належить до родини SHA-2, стандартизованої NIST, і є основою відбитків TLS-сертифікатів, ідентифікаторів комітів Git, заголовків блоків Bitcoin та перевірки цілісності файлів. Алгоритм використовує конструкцію Меркля-Дамгора з 64 раундами стиснення для отримання 256-бітного виводу.
deployment-v4.2.1
a1f7c3d8e9b2...27ae41e4649b (64 hex chars)
Наведений вище hex-дайджест — стандартне представлення: 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-символьний шістнадцятковий рядок. Використовуйте .digest() при передачі результату в HMAC, Base64-кодування або бінарні протоколи. Використовуйте .hexdigest() для журналювання, стовпців бази даних і порівняння контрольних сум.HMAC-SHA256 — хешування з ключем через модуль hmac
SHA-256 сам по собі не підтримує секретний ключ — будь-хто з тими самими вхідними даними може обчислити той самий хеш. Якщо потрібно підтвердити, що повідомлення надійшло від конкретного відправника (верифікація вебхуків, підпис API-запитів, автентифікація токенів), вам потрібен HMAC. Модуль hmac входить до стандартної бібліотеки Python і вбудовує ключ у процес хешування так, що лише той, хто має ключ, може створити або перевірити однаковий дайджест.
import hmac
import hashlib
# Верифікація підпису вебхука
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-символьний hex HMAC-SHA256 дайджестДля перевірки вхідного HMAC потрібно використовувати hmac.compare_digest() замість оператора ==. Оператор рівності вразливий до атак за часом — він перериває порівняння на першому невідповідному байті, і зловмисник може вимірювати час відповіді, щоб вгадати правильний підпис байт за байтом. compare_digest() виконується за постійний час незалежно від місця невідповідності.
import hmac
import hashlib
def verify_webhook(payload: bytes, received_sig: str, secret: bytes) -> bool:
"""Перевіряє підпис вебхука за допомогою порівняння за постійним часом."""
expected = hmac.new(secret, payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received_sig)
# Симуляція верифікації вебхука у стилі Stripe
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("Підпис не збігається — відхиляємо запит")Підпис API-запитів з 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:
"""Створює HMAC-SHA256 підпис для API-запиту."""
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...HMAC-SHA256 у кодуванні Base64
Деякі API (AWS Signature V4, різні платіжні шлюзи) очікують результат HMAC у вигляді рядка Base64, а не шістнадцяткового. Різниця: hex використовує 64 символи, Base64 — 44 символи для того самого 32-байтного дайджесту.
import hmac
import hashlib
import base64
secret = b"webhook_secret_9f3a"
message = b"POST /api/v2/events 1741614120"
# Вивід у hex: 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, датакласи, моделі Pydantic — необхідно серіалізувати у байти перед хешуванням. Автоматичного перетворення немає; ви самі обираєте канонічне представлення. Для детермінованого хешування між різними системами завжди використовуйте явне кодування та стабільний формат серіалізації (ISO 8601 для datetime, стандартний рядковий формат для UUID, JSON із сортуванням ключів для словників).
import hashlib
import uuid
from datetime import datetime, timezone
# datetime — використовуйте ISO 8601 з явним UTC зміщенням для сумісності
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 hash: {time_hash[:16]}...")
# UUID — хешуємо канонічний рядок (нижній регістр, з дефісами)
record_id = uuid.uuid4()
uuid_hash = hashlib.sha256(str(record_id).encode("utf-8")).hexdigest()
print(f"UUID hash: {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 із сортуванням ключів для детермінізму."""
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) при хешуванні JSON-серіалізованих об'єктів. Порядок вставки у словниках зберігається в Python 3.7+, але може відрізнятися між різними шляхами серіалізації, що призводить до різних хешів для однакових даних.Контрольна сума SHA-256 файлу — верифікація завантажень та артефактів
Обчислення контрольної суми SHA-256 файлу є одним із найпоширеніших використань алгоритму. Ви зустрічаєте це всюди: на сторінках релізів бінарних файлів Go, wheel-пакетів Python, маніфестів Docker-образів, оновлень прошивок. Головне — читати файл порціями, а не завантажувати його повністю: 2 ГБ ISO-образ не повинен вимагати 2 ГБ оперативної пам'яті лише для його хешування.
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(), яка виконує читання порціями всередині і може використовувати оптимізації zero-copy на підтримуваних платформах. Якщо ви працюєте на версії 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 (Subresource Integrity у браузерах) використовують Base64, а JWT-підписи кодуються у Base64url. Важливо: Base64 кодується з необроблених байтів .digest(), а не з шістнадцяткового рядка.
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"Wrong length: {len(wrong)} chars") # 88 — не те, чого очікують API.digest(), а не .hexdigest(), перед Base64-кодуванням.Довідник hashlib.sha256()
Конструктор та методи об'єкта SHA-256 хешу:
Параметри hmac.new() для хешування з ключем:
Бібліотека cryptography — альтернативний SHA-256 API
Пакет cryptography надає інший API для SHA-256 через свої hazmat-примітиви. Я рідко звертаюся до нього, коли потрібен лише хеш — 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-символьний hex рядок # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
cryptography потребує pip install cryptography. Об'єкт хешу є одноразовим: повторний виклик .finalize() спричинює AlreadyFinalized. Використовуйте .copy() перед фіналізацією, якщо потрібно розгалужити стан хешу.Хешування даних із файлу та відповіді API
Два сценарії виникають постійно: хешування файлу на диску для верифікації артефакту релізу та хешування тіла HTTP-відповіді для використання як ключа кешу або перевірки вебхука.
Читання файлу → обчислення 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]:
"""Отримує JSON з API та повертає і дані, і їхній 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"Response hash: {digest[:16]}...")
print(f"EUR/USD: {data.get('rates', {}).get('EUR', 'N/A')}")Для швидкої разової перевірки SHA-256 генератор ToolDeck працює повністю у вашому браузері — жодного коду не потрібно.
SHA-256 хешування в командному рядку
Іноді під час інциденту або розгортання потрібен швидкий хеш прямо в терміналі. Модуль hashlib у Python не має вбудованої CLI-підкоманди (на відміну від 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 і в оболонці.Висока продуктивність — hashlib з OpenSSL та pycryptodome
У CPython hashlib.sha256() вже делегує роботу C-реалізації OpenSSL, тому він швидкий — як правило, 500+ МБ/с на сучасному залізі.
Якщо SHA-256 хешування з'являється у вашому профайлері — наприклад, ви обчислюєте контрольні суми для тисяч файлів у CI-конвеєрі або хешуєте кожне тіло запиту у високонавантаженому API-шлюзі — існують два варіанти: оптимізувати схему викликів hashlib або перейти на pycryptodome для уніфікованого криптографічного API, що охоплює також SHA-3 і BLAKE2:
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]:
"""Хешує один файл і повертає (шлях, hex дайджест)."""
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""): # порції по 64 КБ
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 КБ замість 8 КБ скорочує кількість викликів Python→C у 8 разів. Потоки добре підходять тут, оскільки GIL знімається під час хешування на рівні C — вузьким місцем є дисковий ввід-вивід, а не процесор.
Кольоровий вивід у терміналі
Бібліотека rich корисна, коли потрібно верифікувати пакет файлів і відобразити таблицю зі статусом pass/fail для кожного файлу замість простого виводу hex-рядків.
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 Verification")
table.add_column("File", style="cyan")
table.add_column("SHA-256", style="dim", max_width=20)
table.add_column("Status")
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]✗ MISMATCH[/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() обробляє файли будь-якого розміру з постійним використанням пам'яті. Для дуже великих файлів (багатогігабайтні образи дисків, резервні копії баз даних) основне питання зміщується від пам'яті до зворотного зв'язку з користувачем — хешування 10 ГБ зі швидкістю 500 МБ/с займає 20 секунд, і мовчання протягом цього часу турбує.
import hashlib
import os
def sha256_with_progress(filepath: str) -> str:
"""Хешує великий файл з відображенням прогресу у 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): # порції по 1 МБ
h.update(chunk)
bytes_read += len(chunk)
pct = (bytes_read / file_size) * 100
print(f"\r Хешування: {pct:.1f}% ({bytes_read >> 20} МБ / {file_size >> 20} МБ)",
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]:
"""Хешує кожен JSON-запис у файлі NDJSON для дедуплікації."""
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(), коли файли перевищують 50–100 МБ. Нижче цього порогу читання всього файлу через 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-символьний hex рядокПроблема: Оператор == перериває порівняння на першому невідповідному байті. Зловмисник може вимірювати час відповіді для вгадування правильного підпису байт за байтом.
Рішення: Використовуйте 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 символи. API, що очікують Base64-кодований SHA-256, відхиляють його.
Рішення: Викликайте .digest() (необроблені байти) перед Base64-кодуванням, а не .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 ГБ вимагає 4 ГБ оперативної пам'яті лише для обчислення хешу.
Рішення: Читайте файл порціями у циклі з .update(). Використання пам'яті залишається постійним незалежно від розміру файлу.
import hashlib
# Завантажує весь файл 4 ГБ у пам'ять
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(). Переходьте до hmac.new() у той момент, коли потрібен секретний ключ (вебхуки, підписи API, автентифікація токенів). Звертайтеся до бібліотеки cryptography лише якщо ваш проект вже використовує її для шифрування або TLS — додавати C-розширення лише заради хешування надлишково, коли hashlib вже реалізований через OpenSSL.
Чи можна розшифрувати SHA-256? — Хешування vs шифрування
Коротка відповідь: ні. SHA-256 — це одностороння функція. Алгоритм розроблений як незворотний — ви не можете відновити вихідні дані з 256-бітного дайджесту. Це не обмеження реалізації; це математична властивість хеш-функції. Простір виводу у 256 бітів є астрономічно великим (2256 можливих значень), а функція втрачає інформацію під час 64 раундів стиснення.
Зловмисники можуть спробувати атаки грубою силою або за словником проти слабких вхідних даних (поширені паролі, короткі рядки), але для будь-яких вхідних даних із достатньою ентропією — ключів API, випадкових токенів, вмісту файлів — відновлення SHA-256 є обчислювально неможливим на сучасному залізі. Якщо вам потрібне оборотне перетворення, використовуйте симетричне шифрування:
# Хешування — одностороннє, не можна відновити оригінал import hashlib digest = hashlib.sha256(b"secret-config-value").hexdigest() # Немає способу отримати "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 хеш без встановлення пакетів онлайн-інструмент працює повністю у вашому браузері.
Як перевірити, чи є рядок коректним SHA-256 хешем у Python
Коректний SHA-256 hex-дайджест — це рівно 64 шістнадцяткових символи (0-9, a-f, A-F). Швидка перевірка перед обробкою ненадійних вхідних даних запобігає заплутаним помилкам на пізніших етапах.
import re
def is_sha256_hex(value: str) -> bool:
"""Перевіряє, чи відповідає рядок формату SHA-256 hex-дайджесту."""
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 — некоректні hex-символиЧасті запитання
Як хешувати рядок за допомогою SHA-256 у Python?
Викличте 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 hex charactersЧи можна розшифрувати SHA-256 хеш назад до початкового тексту?
Ні. SHA-256 — це одностороння функція: вона перетворює вхідні дані довільної довжини на фіксований 256-бітний вивід і безповоротно втрачає вихідну структуру. Математичного зворотного перетворення не існує. Зловмисники можуть спробувати грубу силу або атаки за допомогою райдужних таблиць проти слабких вхідних даних (короткі паролі, поширені слова), але для будь-якого вхідного значення з достатньою ентропією відновлення SHA-256 є обчислювально неможливим. Якщо вам потрібне оборотне перетворення, використовуйте шифрування (AES-GCM, Fernet), а не хешування.
У чому різниця між .digest() та .hexdigest()?
.digest() повертає необроблені 32 байти хешу як об'єкт bytes. .hexdigest() повертає ті самі дані, закодовані як 64-символьний рядок у нижньому регістрі шістнадцяткового формату. Використовуйте .digest(), коли потрібен бінарний вивід — для передачі в HMAC, Base64-кодування або запис у бінарні протоколи. Використовуйте .hexdigest(), коли потрібен читабельний рядок для журналювання, збереження в базі даних або порівняння контрольних сум.
import hashlib h = hashlib.sha256(b"deployment-v4.2.1") print(len(h.digest())) # 32 (bytes) print(len(h.hexdigest())) # 64 (hex characters)
Як обчислити контрольну суму SHA-256 файлу в Python?
Відкрийте файл у бінарному режимі та передавайте його до хешера порціями через .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"))Як створити підпис HMAC-SHA256 у Python?
Використовуйте модуль hmac з hashlib.sha256 як digestmod. Передайте секретний ключ і повідомлення у вигляді байтів. Результат — це хеш із ключем, який підтверджує як цілісність, так і автентичність: отримувач повинен мати той самий ключ для перевірки.
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-char hex HMACЯк перевірити, чи є рядок коректним SHA-256 hex-дайджестом?
SHA-256 hex-дайджест — це рівно 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.