SHA-256 в Python — руководство по hashlib + примеры

·DevOps Engineer & Python Automation Specialist·ПровереноMaria Santos·Опубликовано

Используйте бесплатный 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-битного вывода.

Before · text
After · text
deployment-v4.2.1
a1f7c3d8e9b2...27ae41e4649b (64 hex chars)

Показанный выше hex-дайджест — стандартное представление: 64 шестнадцатеричных символа, одинаковой длины независимо от того, хешируется один байт или целый образ диска.

hashlib.sha256() — подход стандартной библиотеки

Модуль hashlib входит в каждую установку Python — никакого pip install не требуется. Вызовите hashlib.sha256() с аргументом типа bytes для создания объекта хеша, затем получите результат через .hexdigest() (hex-строка) или .digest() (сырые байты). Имя функции пишется в нижнем регистре: sha256, а не SHA256.

Python 3.9+ — минимальный SHA-256 хеш
import hashlib

# Хеширование байтовой строки напрямую
digest = hashlib.sha256(b"deployment-v4.2.1").hexdigest()
print(digest)
# a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db

Наиболее распространённая ошибка при работе с hashlib.sha256() — передача str вместо bytes. Строки Python — это Unicode, а хеш-функции работают с сырыми байтами. Необходимо вызвать .encode("utf-8") перед хешированием. На этом спотыкаются почти все при первом знакомстве.

Python 3.9+ — хеширование строки
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). Именно так хешируются файлы по частям без загрузки всего содержимого в память.

Python 3.9+ — инкрементное хеширование через update()
import hashlib

h = hashlib.sha256()
h.update(b"request_id=req_7f3a91bc")
h.update(b"&timestamp=1741614120")
h.update(b"&amount=4999")
print(h.hexdigest())
# Эквивалентно hashlib.sha256(b"request_id=req_7f3a91bc&timestamp=1741614120&amount=4999").hexdigest()
Примечание:.digest() возвращает сырые 32 байта. .hexdigest() возвращает 64-символьную hex-строку. Используйте .digest() при передаче результата в HMAC, кодирование Base64 или двоичные протоколы. Используйте .hexdigest() для логирования, колонок базы данных и сравнения контрольных сумм.

HMAC-SHA256 — хеширование с ключом через модуль hmac

SHA-256 сам по себе не использует секретный ключ — любой, кто знает входные данные, может вычислить тот же хеш. Если нужно доказать, что сообщение пришло от конкретного отправителя (верификация вебхуков, подпись API-запросов, аутентификация токенов), необходим HMAC. Модуль hmac входит в стандартную библиотеку Python и встраивает ключ в процесс хеширования, так что только тот, кто знает ключ, может создать или проверить тот же дайджест.

Python 3.9+ — базовый HMAC-SHA256
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() выполняется за постоянное время независимо от места несовпадения.

Python 3.9+ — проверка подписи вебхука
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 — все они используют вариации этого паттерна.

Python 3.9+ — подпись API-запроса с HMAC-SHA256
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. Разница: hex использует 64 символа, Base64 — 44 символа для того же 32-байтового дайджеста.

Python 3.9+ — HMAC-SHA256 с кодированием Base64
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 работает с сырыми байтами, поэтому типы, отличные от bytes — datetime, UUID, датаклассы, модели Pydantic — необходимо сериализовать в байты перед хешированием. Автоматического преобразования нет; выбор канонического представления за вами. Для детерминированного хеширования между системами всегда используйте явную кодировку и стабильный формат сериализации (ISO 8601 для datetime, стандартную строковую форму для UUID, JSON с отсортированными ключами для словарей).

Python 3.9+ — хеширование datetime и UUID
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 с отсортированными ключами хорошо подходит для словарей и подобных объектов:

Python 3.9+ — хеширование произвольного объекта
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, обновления прошивки. Ключевое правило — читать файл по частям, а не загружать целиком: для хеширования ISO-образа объёмом 2 ГБ не должно требоваться 2 ГБ оперативной памяти.

Python 3.9+ — контрольная сумма SHA-256 файла (по частям)
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 на поддерживаемых платформах. Если вы работаете на Python 3.11 или новее, отдайте предпочтение ей перед ручным циклом.

Python 3.11+ — hashlib.file_digest()
import hashlib

with open("/tmp/release-v4.2.1.tar.gz", "rb") as f:
    digest = hashlib.file_digest(f, "sha256")

print(digest.hexdigest())

Проверка загруженного файла по известной контрольной сумме

Python 3.9+ — верификация контрольной суммы
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, а не hex. HTTP-заголовки Content-Digest и Integrity (Subresource Integrity в браузерах) используют Base64, а подписи JWT кодируются в Base64url. Важно применять Base64-кодирование к сырым байтам из .digest(), а не к hex-строке.

Python 3.9+ — SHA-256 с кодированием 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 от hex-строки (64 ASCII-байта → 88 символов Base64 — вдвое больше)
hex_digest = hashlib.sha256(data).hexdigest()
wrong = base64.b64encode(hex_digest.encode()).decode()
print(f"Неверная длина: {len(wrong)} символов")  # 88 — не то, что ожидают API
Предупреждение:Кодирование hex-строки в Base64 вместо сырых байтов — распространённая ошибка, дающая вывод вдвое больше ожидаемого. API отклонит такой результат, причём сообщение об ошибке обычно не указывает на причину. Всегда вызывайте .digest(), а не .hexdigest(), перед кодированием в Base64.

Справочник hashlib.sha256()

Конструктор и методы объекта хеша SHA-256:

Параметр / Метод
Тип
Описание
data (позиционный)
bytes
Начальные данные для хеширования — эквивалентно вызову update(data) сразу после создания объекта
.update(data)
bytes
Передаёт дополнительные байты в состояние хеша — можно вызывать многократно для порционного ввода
.digest()
→ bytes
Возвращает сырой 32-байтовый двоичный дайджест — используется для входных данных HMAC, двоичных протоколов, кодирования Base64
.hexdigest()
→ str
Возвращает 64-символьную строку в нижнем регистре hex — стандартное представление для контрольных сумм и проверки
.copy()
→ hash object
Возвращает копию текущего состояния хеша — позволяет разветвить дайджест без повторного хеширования с нуля
hashlib.sha256()
constructor
Создаёт новый объект хеша SHA-256 на основе OpenSSL в CPython — usedfips=True в Python 3.9+ ограничивает использование алгоритмами, одобренными FIPS

Параметры hmac.new() для хеширования с ключом:

Параметр
Тип
Описание
key
bytes
Секретный ключ — должен быть bytes, не str
msg
bytes | None
Начальное сообщение для аутентификации — по умолчанию None, можно вызвать update() позже
digestmod
str | callable
Алгоритм хеширования: передайте hashlib.sha256 или строку "sha256"

Библиотека cryptography — альтернативный API для SHA-256

Пакет cryptography предоставляет другой API для SHA-256 через низкоуровневые примитивы hazmat. Когда нужен просто хеш, я редко к нему обращаюсь — hashlib проще и не требует внешних зависимостей. Но если ваш проект уже использует cryptography для TLS, X.509 или симметричного шифрования, применение его хеш-API сохраняет единообразие в рамках одной библиотеки и обеспечивает согласованную обработку ошибок.

Python 3.9+ — SHA-256 с библиотекой cryptography
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 → сравнение

Python 3.9+ — хеширование резервной копии конфига с обработкой ошибок
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-ответ → хеширование тела для ключа кеша

Python 3.9+ — хеширование ответа API
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"Хеш ответа: {digest[:16]}...")
print(f"EUR/USD: {data.get('rates', {}).get('EUR', 'N/A')}")

Для быстрой одноразовой проверки генератор SHA-256 от ToolDeck работает полностью в браузере — без написания кода.

SHA-256 хеширование в командной строке

Иногда во время инцидента или развёртывания нужно быстро вычислить хеш прямо в терминале. Модуль hashlib не имеет встроенной подкоманды CLI (в отличие от python3 -m json.tool), но можно воспользоваться однострочником или системными утилитами.

bash — хеширование строки из командной строки
# Однострочник 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
bash — хеширование файла
# Хешируем архив релиза
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() уже делегирует вычисления реализации OpenSSL на C, поэтому работает быстро — как правило, более 500 МБ/с на современном оборудовании.

Если SHA-256 хеширование появляется в профилировщике — например, вы вычисляете контрольные суммы тысяч файлов в CI-конвейере или хешируете тело каждого запроса в высоконагруженном API-шлюзе — есть два варианта: оптимизировать паттерн вызова hashlib или переключиться на pycryptodome — унифицированный криптографический API, охватывающий также SHA-3 и BLAKE2:

bash — установка pycryptodome
pip install pycryptodome
Python 3.9+ — SHA-256 с pycryptodome
from Crypto.Hash import SHA256

h = SHA256.new()
h.update(b"deployment-v4.2.1")
print(h.hexdigest())
# a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db

При параллельном хешировании большого количества файлов наибольший выигрыш даёт снижение накладных расходов Python за счёт увеличения размера блока и многопоточности:

Python 3.9+ — пакетное хеширование файлов с hashlib
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 удобна, когда нужно проверить пакет файлов и отобразить таблицу со статусом прохождения/отказа для каждого файла, а не листать мелькающие hex-строки в терминале.

bash — установка rich
pip install rich
Python 3.9+ — цветной вывод результатов верификации через 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,
)
Примечание:Вывод rich предназначен только для терминала. Не записывайте ANSI-коды в лог-файлы или API-ответы — отключите их с помощью console.print(data, highlight=False) или перенаправьте в файл через Console(file=open(...)).

Работа с большими файлами

Порционный паттерн с .update() обрабатывает файлы любого размера при постоянном потреблении памяти. Для очень больших файлов (многогигабайтные образы дисков, резервные копии баз данных) основная забота смещается от памяти к обратной связи с пользователем — хеширование 10 ГБ при 500 МБ/с занимает 20 секунд, и тишина в это время нервирует.

Python 3.9+ — хеширование больших файлов с отображением прогресса
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 — хеширование каждой записи отдельно

Python 3.9+ — хеширование отдельных записей в потоке NDJSON
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() допустимо — потребление памяти будет примерно равно размеру файла.

Распространённые ошибки

Передача str вместо bytes в hashlib.sha256()

Проблема: hashlib.sha256('text') вызывает TypeError: Unicode-objects must be encoded before hashing. Функция требует bytes, а не str.

Решение: Закодируйте строку сначала: hashlib.sha256('text'.encode('utf-8')). Или используйте литерал b'' для жёстко заданных значений.

Before · Python
After · Python
import hashlib
digest = hashlib.sha256("deployment-v4.2.1").hexdigest()
# TypeError: Unicode-objects must be encoded before hashing
import hashlib
digest = hashlib.sha256("deployment-v4.2.1".encode("utf-8")).hexdigest()
# Работает — возвращает 64-символьную hex-строку
Использование == вместо hmac.compare_digest() при верификации подписи

Проблема: Оператор == прерывается при первом несовпадающем байте. Злоумышленник может измерять время ответа и угадывать правильную подпись побайтово.

Решение: Используйте hmac.compare_digest() для всех сравнений, чувствительных к безопасности — он выполняется за постоянное время независимо от места несовпадения.

Before · Python
After · Python
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)
Кодирование hex-строки в Base64 вместо сырых байтов

Проблема: base64.b64encode(digest.hexdigest().encode()) даёт 88-символьную строку — вдвое больше ожидаемых 44 символов. API, ожидающие Base64-кодированный SHA-256, отклонят такой результат.

Решение: Вызывайте .digest() (сырые байты) перед кодированием в Base64, а не .hexdigest() (hex-строка).

Before · Python
After · Python
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(). Потребление памяти остаётся постоянным независимо от размера файла.

Before · Python
After · Python
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()
hex / bytes
Быстро (C/OpenSSL)
✓ через update()
Нет (stdlib)
Ручной encode()
hmac.new()
hex / bytes
Быстро (C/OpenSSL)
✓ через update()
Нет (stdlib)
Ручной encode()
hashlib.file_digest()
hex / bytes
Быстро (zero-copy)
✓ (встроено)
Нет (3.11+)
Ручной encode()
cryptography hashes.SHA256()
bytes
Быстро (OpenSSL)
✓ через update()
pip install
Ручной encode()
subprocess openssl dgst
hex string
✗ / ✓
Медленнее (fork)
✓ (уровень ОС)
System openssl
Ручной encode()
pyhashcat / custom
varies
GPU-ускорение
pip install
Ручной encode()

Для простого хеширования — контрольные суммы, ключи кеша, отпечатки содержимого — используйте hashlib.sha256(). Переходите на hmac.new() как только потребуется секретный ключ (вебхуки, подписи API, аутентификация токенов). Обращайтесь к библиотеке cryptography только если проект уже использует её для шифрования или TLS — добавлять зависимость от C-расширения только ради хеширования избыточно, когда hashlib уже использует OpenSSL.

Можно ли расшифровать SHA-256? — хеширование против шифрования

Короткий ответ: нет. SHA-256 — это односторонняя функция. Алгоритм спроектирован необратимым — восстановить исходные входные данные из 256-битного дайджеста невозможно. Это не ограничение реализации, а математическое свойство хеш-функции. Пространство 256-битного вывода астрономически велико (2256 возможных значений), и функция теряет информацию в процессе 64 раундов сжатия.

Злоумышленники могут применять перебор или атаки по словарю против слабых входных данных (распространённые пароли, короткие строки), однако для любых входных данных с достаточной энтропией — API-ключи, случайные токены, содержимое файлов — обращение SHA-256 вычислительно невозможно на современном оборудовании. Если нужно обратимое преобразование, используйте симметричное шифрование:

Python 3.9+ — шифрование против хеширования
# Хеширование — одностороннее, исходные данные не восстановить
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

Корректный hex-дайджест SHA-256 состоит ровно из 64 шестнадцатеричных символов (0-9, a-f, A-F). Быстрая проверка перед обработкой недоверенных входных данных предотвращает запутанные ошибки на последующих этапах.

Python 3.9+ — проверка формата SHA-256
import re

def is_sha256_hex(value: str) -> bool:
    """Проверяет, соответствует ли строка формату hex-дайджеста 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 — недопустимые hex-символы
Примечание:Это проверка только формата, но не того, был ли хеш вычислен из конкретных входных данных. Невозможно определить, является ли 64-символьная hex-строка "настоящим" SHA-256 дайджестом или просто случайными hex-данными — по замыслу вывод SHA-256 неотличим от случайных данных.

Часто задаваемые вопросы

Как захешировать строку с помощью SHA-256 в Python?

Вызовите hashlib.sha256() со строкой, закодированной в байты. Строки в Python — это Unicode, а хеш-функции работают с сырыми байтами, поэтому сначала необходимо вызвать .encode("utf-8"). Метод .hexdigest() возвращает привычную 64-символьную hex-строку.

Python
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-символьной строки в нижнем регистре hex. Используйте .digest(), когда нужен двоичный вывод — для передачи в HMAC, кодирования Base64 или записи в двоичные протоколы. Используйте .hexdigest(), когда нужна читаемая строка для логирования, хранения в базе данных или сравнения контрольных сумм.

Python
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() для больших файлов — это загружает весь файл в память.

Python
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. Передайте секретный ключ и сообщение в виде байтов. Результат — хеш с ключом, который доказывает как целостность, так и подлинность: получатель должен иметь тот же ключ для проверки.

Python
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

Как проверить, является ли строка корректным hex-дайджестом SHA-256?

Hex-дайджест SHA-256 состоит ровно из 64 шестнадцатеричных символов. Используйте регулярное выражение или простую проверку длины и состава символов. Подход с регулярным выражением наиболее читаем.

Python
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

Похожие инструменты

DV
Dmitri VolkovDevOps Engineer & Python Automation Specialist

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.

MS
Maria SantosТехнический рецензент

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.