HMAC v Pythonu — průvodce hmac.new() SHA-256 + příklady kódu

·DevOps Engineer & Python Automation Specialist·ZkontrolovánoMaria Santos·Publikováno

Používejte bezplatný HMAC Generator přímo v prohlížeči — bez instalace.

Vyzkoušet HMAC Generator online →

Každý webhook callback, každý podepsaný API požadavek, každé oznámení od Stripe nebo GitHubu používá HMAC podpisk prokázání, že payload nebyl pozměněn. Python's hmac modul zpracovává HMAC-SHA256 v Pythonu jediným voláním funkce: hmac.new(key, msg, hashlib.sha256). Žádný pip install, žádné C rozšíření, žádná závislost na třetích stranách. Pro rychlé jednorázové kontroly podpisů bez psaní kódu vám online generátor HMAC poskytne výsledek okamžitě. Tento průvodce pokrývá hmac.new(), hmac.digest(), hmac.compare_digest(), Base64 kódování, ověřování webhooků, podepisování API požadavků a každý hashovací algoritmus od SHA-1 po SHA-512. Všechny příklady cílí na Python 3.7+.

  • hmac.new(key, msg, hashlib.sha256) je standardní vstupní bod — key a msg musí být bytes, digestmod je povinný od Pythonu 3.4.
  • hmac.digest(key, msg, "sha256") je rychlejší jednorázová alternativa přidaná v Pythonu 3.7 — vrací surové bajty bez meziobjektu.
  • Vždy ověřujte podpisy pomocí hmac.compare_digest() pro prevenci časovacích útoků — nikdy nepoužívejte == pro porovnání HMAC.
  • Base64-enkódujte surový výstup .digest() pro HTTP hlavičky a podpisy webhooků: base64.b64encode(h.digest()).
  • Modul hmac přijímá libovolný algoritmus hashlib: sha1, sha256, sha384, sha512, md5, blake2b.

Co je HMAC?

HMAC (Hash-based Message Authentication Code) je konstrukce definovaná v RFC 2104 která kombinuje tajný klíč s hashovací funkcí pro vytvoření autentizační značky pevné délky. Na rozdíl od prostého hashe (který může kdokoli vypočítat) vyžaduje HMAC znalost tajného klíče. To znamená, že ho můžete použít k ověření jak integrity, tak autentičnosti zprávy. Pokud se změní byť jediný bajt zprávy nebo klíče, výstup bude zcela odlišný. Konstrukce funguje tak, že hashuje klíč XORovaný se dvěma různými konstantami výplně (ipad a opad) a obaluje zprávu mezi dvě hashovací operace. Python's hmac modul implementuje toto RFC přímo.

Before · Python
After · Python
# Prostý SHA-256 hash — bez tajného klíče, kdokoli může vypočítat
hashlib.sha256(b"payment:9950:USD").hexdigest()
# "7a3b1c..."  (deterministický, veřejný)
# HMAC-SHA256 — vyžaduje tajný klíč k výpočtu
hmac.new(b"api_secret", b"payment:9950:USD", hashlib.sha256).hexdigest()
# "e4f2a8..."  (může vypočítat pouze držitel klíče)

hmac.new() — vstupní bod standardní knihovny

Modul hmac je součástí standardní knihovny Pythonu. Dva importy a jste připraveni: import hmac, hashlib. Tři hlavní funkce jsou hmac.new() (vytvoří objekt HMAC), hmac.digest() (jednorázové, Python 3.7+) a hmac.compare_digest() (porovnání v konstantním čase). Žádný pip install není potřeba.

hmac.new(key, msg, digestmod) přijímá tři argumenty. Jak key, tak msg musí být objekty podobné bajtům ( bytes, bytearray nebo memoryview). Argument digestmod je povinný od Pythonu 3.4 a přijímá libovolný konstruktor hashlib (jako hashlib.sha256) nebo řetězcový název jako "sha256".

Python 3.7+ — minimální příklad HMAC-SHA256
import hmac
import hashlib

key = b"webhook_signing_key_2026"
message = b'{"event":"invoice.paid","invoice_id":"inv_8f3a","amount":19900}'

# Vytvoření objektu HMAC a získání hex podpisu
signature = hmac.new(key, message, hashlib.sha256).hexdigest()
print(signature)
# "b4e74f6c9a1d3e5f8b2a7c0d4e6f1a3b5c7d9e0f2a4b6c8d0e1f3a5b7c9d0e2f"

Objekt HMAC nabízí dvě výstupní metody. .digest() vrací surové bajty (32 bajtů pro SHA-256, 64 pro SHA-512). .hexdigest() vrací hex řetězec malými písmeny. Hex řetězec je prostý Python str — není potřeba žádný krok dekódování.

Python 3.7+ — .digest() vs .hexdigest()
import hmac
import hashlib

key = b"service_auth_key"
msg = b"GET /api/v2/orders 2026-03-28T14:30:00Z"

h = hmac.new(key, msg, hashlib.sha256)

raw_bytes = h.digest()
print(type(raw_bytes), len(raw_bytes))
# <class 'bytes'> 32

hex_string = h.hexdigest()
print(type(hex_string), len(hex_string))
# <class 'str'> 64

# Představují stejná data — hex je pouze řetězcové kódování bajtů
assert raw_bytes.hex() == hex_string

Pokud je váš klíč nebo zpráva Python řetězec, zavolejte .encode() pro převod na bajty před předáním do hmac.new(). Na toto narazí téměř každý napoprvé — řetězce v Pythonu 3 jsou Unicode, nikoli bajty, a modul hmac je odmítá.

Python 3.7+ — kódování řetězců na bajty
import hmac
import hashlib

# Řetězcový klíč a zpráva — .encode() převede na UTF-8 bajty
api_key = "sk_live_9f3a2b7c4d8e"
request_body = '{"customer_id":"cust_4421","plan":"enterprise"}'

signature = hmac.new(
    api_key.encode(),
    request_body.encode(),
    hashlib.sha256
).hexdigest()

print(signature)
# "3a9f1b..."  — konzistentní hex řetězcový výstup
Poznámka:Parametr digestmod nemá výchozí hodnotu od Pythonu 3.4. Volání hmac.new(key, msg) bez něj vyvolá TypeError. Před verzí 3.4 byl výchozí hodnotou MD5, proto správci Pythonu výchozí hodnotu odstranili — nutí vás učinit explicitní, bezpečnou volbu.

HMAC-SHA256 Base64, SHA-1, SHA-512 a MD5

Funkce hmac.new() pracuje s libovolným hashovacím algoritmem dostupným v hashlib. Většina poskytovatelů webhooků a API bran používá HMAC-SHA256, ale setkáte se se SHA-1 v OAuth 1.0a, SHA-512 v protokolech, které ho vyžadují, a MD5 ve starších systémech, které nebyly aktualizovány.

HMAC-SHA256 s Base64 výstupem

Mnoho poskytovatelů webhooků odesílá podpis jako Base64-enkódovaný řetězec v HTTP hlavičce. Chcete-li vytvořit stejný formát, předejte surové bajty .digest() do base64.b64encode().

Python 3.7+ — HMAC-SHA256 Base64 kódování
import hmac
import hashlib
import base64

key = b"whsec_MbkP7x9yFqHGn3tRdWz5"
payload = b'{"id":"evt_1Nq","type":"charge.succeeded","data":{"amount":4200}}'

# Surový digest → Base64 (běžné pro Authorization hlavičky a podpisy webhooků)
raw_digest = hmac.new(key, payload, hashlib.sha256).digest()
b64_signature = base64.b64encode(raw_digest).decode("ascii")

print(b64_signature)
# "dGhpcyBpcyBhIHNhbXBsZSBzaWduYXR1cmU="

# Toto je hodnota, kterou byste porovnávali s hlavičkou X-Signature
header_value = f"sha256={b64_signature}"
print(header_value)
# "sha256=dGhpcyBpcyBhIHNhbXBsZSBzaWduYXR1cmU="

HMAC-SHA1 — kompatibilita se staršími protokoly

SHA-1 je považován za slabý pro nové návrhy, ale HMAC-SHA1 je stále vyžadován OAuth 1.0a a některými staršími implementacemi webhooků. Kód je identický — stačí zaměnit algoritmus.

Python 3.7+ — HMAC-SHA1
import hmac
import hashlib

consumer_secret = b"oauth_consumer_secret_2026"
token_secret = b"oauth_token_secret_2026"

# OAuth 1.0a používá consumer_secret&token_secret jako podpisový klíč
signing_key = consumer_secret + b"&" + token_secret
base_string = b"GET&https%3A%2F%2Fapi.service.com%2Fv1%2Forders&oauth_nonce%3D7f3a91bc"

sig = hmac.new(signing_key, base_string, hashlib.sha1).digest()

import base64
oauth_signature = base64.b64encode(sig).decode("ascii")
print(oauth_signature)
# "Tza3R9sE..."  — URL-enkódujte pro hlavičku Authorization

HMAC-SHA512 — delší výstup

Python 3.7+ — HMAC-SHA512
import hmac
import hashlib

key = b"high_security_signing_key_64_bytes_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
msg = b'{"transfer_id":"xfr_9c2e","amount":500000,"currency":"EUR"}'

h = hmac.new(key, msg, hashlib.sha512)

print(len(h.digest()))   # 64 bajtů (512 bitů)
print(len(h.hexdigest()))  # 128 hex znaků
print(h.hexdigest()[:40] + "...")
# "8e3a1f9b2c4d6e7f0a1b3c5d7e9f0a2b4c6d8e0f..."

HMAC-MD5 — pouze pro starší systémy

Python 3.7+ — HMAC-MD5
import hmac
import hashlib

# MD5 je kryptograficky prolomen — používejte pouze pro kompatibilitu se starými protokoly
key = b"legacy_api_key"
msg = b"action=charge&amount=1500&merchant=store_42"

sig = hmac.new(key, msg, hashlib.md5).hexdigest()
print(sig)  # 32znakový hex řetězec
# "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Varování:HMAC-MD5 je přijatelný pouze pro zpětnou kompatibilitu se systémy, které nelze migrovat. Pro jakýkoli nový projekt používejte minimálně HMAC-SHA256. MD5 má známé kolizní zranitelnosti, které, ačkoli jsou v režimu HMAC méně přímo zneužitelné, z něj dělají špatnou výchozí volbu.

Referenční přehled parametrů hmac.new()

Signatura konstruktoru je hmac.new(key, msg=None, digestmod). Všechny tři funkce v modulu sdílejí stejný vzor pro argumenty klíče a algoritmu.

konstruktor hmac.new()

Parametr
Typ
Výchozí hodnota
Popis
key
bytes | bytearray
(povinné)
Tajný klíč — musí být bytes, nikoli řetězec
msg
bytes | None
None
Počáteční zpráva k hashování; další data lze přidat přes .update()
digestmod
str | callable
(povinné)
Hashovací algoritmus — např. hashlib.sha256 nebo řetězec "sha256"

hmac.digest() jednorázové (Python 3.7+)

Parametr
Typ
Popis
key
bytes
Tajný klíč
msg
bytes
Zpráva k ověření
digest
str | callable
Hashovací algoritmus — stejný jako digestmod v hmac.new()

Parametr digestmod přijímá buď callable (jako hashlib.sha256) nebo řetězcový název (jako "sha256"). Forma callable je preferována, protože je ověřena při importu — překlep v řetězcové formě selže až za běhu.

hmac.digest() — rychlé jednorázové HMAC (Python 3.7+)

Python 3.7 přidal hmac.digest(key, msg, digest) jako funkci na úrovni modulu. Vypočítá HMAC v jediném volání bez vytváření meziobjektu HMAC. Návratová hodnota jsou surové bajty (ekvivalentní volání .digest() na objektu). Tato funkce používá optimalizovanou implementaci v C na CPythonu a vyhýbá se režii přidělování paměti pro objekt, což ji činí měřitelně rychlejší v soustředěných smyčkách.

Python 3.7+ — hmac.digest() jednorázové
import hmac
import hashlib

key = b"batch_signing_key_2026"
messages = [
    b'{"order_id":"ord_001","total":4500}',
    b'{"order_id":"ord_002","total":8900}',
    b'{"order_id":"ord_003","total":2200}',
]

# Jednorázový digest — bez meziobjektu HMAC
signatures = [hmac.digest(key, msg, hashlib.sha256) for msg in messages]

# Převod na hex pro zobrazení
for msg, sig in zip(messages, signatures):
    print(f"{msg[:30]}... -> {sig.hex()[:24]}...")

Omezení: hmac.digest() vrací pouze surové bajty. Pokud potřebujete hex řetězec přímo, stále potřebujete hmac.new() a jeho metodu .hexdigest(), nebo zřetězte .hex() na výsledek bajtů.

Poznámka:hmac.digest() nepodporuje inkrementální volání .update(). Pokud čtete velký soubor po blocích a potřebujete HMAC obsahu, zůstaňte u hmac.new() a volání .update(chunk) ve smyčce.

Ověření HMAC podpisu z webhooku a API odpovědi

Nejčastějším použitím HMAC v Pythonu je ověřování podpisů webhooků. Každý velký poskytovatel (Stripe, GitHub, Shopify, Twilio) podepisuje payloady pomocí HMAC-SHA256 a odesílá podpis v hlavičce. Vzor je vždy stejný: přepočítejte HMAC nad surovým tělem požadavku, poté porovnejte pomocí hmac.compare_digest().

Ověření podpisu webhooku

Python 3.7+ — ověření HMAC webhooku (Flask)
import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = b"whsec_MbkP7x9yFqHGn3tRdWz5"

@app.route("/webhooks/payments", methods=["POST"])
def handle_payment_webhook():
    # Získání surového těla — musí přesně odpovídat tomu, co bylo podepsáno
    raw_body = request.get_data()

    # Získání podpisu z hlavičky
    received_sig = request.headers.get("X-Signature-256", "")

    # Přepočítání HMAC nad surovým tělem
    expected_sig = hmac.new(WEBHOOK_SECRET, raw_body, hashlib.sha256).hexdigest()

    # Porovnání v konstantním čase — zabraňuje časovacím útokům
    if not hmac.compare_digest(f"sha256={expected_sig}", received_sig):
        abort(403, "Invalid signature")

    # Podpis ověřen — zpracování události
    event = request.get_json()
    print(f"Verified event: {event['type']} for {event['data']['amount']}")
    return "", 200

Funkce hmac.compare_digest() porovnává dva řetězce nebo bytové sekvence v konstantním čase. Běžné porovnání == zkratuje při prvním neshodném bajtu. Útočník může měřit dobu odezvy napříč mnoha požadavky a postupně rekonstruovat očekávaný podpis bajt po bajtu. Porovnání v konstantním čase tento postranní kanál eliminuje.

Ověření GitHub webhooku

Formát webhooku GitHubu ilustruje celý vzor. Odesílá hlavičku X-Hub-Signature-256 obsahující sha256= následovanou hex-enkódovaným HMAC-SHA256 surového těla požadavku, podepsaného tajemstvím webhooku, které nakonfigurujete v nastavení repozitáře. Klíčový rozdíl od obecného ověření webhooku spočívá v tom, že musíte odstranit předponu sha256= před porovnáváním a musíte číst surové bajty těla požadavku — nejprve parsovat JSON změní bajtovou reprezentaci a naruší ověření.

Python 3.7+ — ověření GitHub X-Hub-Signature-256
import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)
GITHUB_WEBHOOK_SECRET = b"your_github_webhook_secret"

@app.route("/webhooks/github", methods=["POST"])
def handle_github_webhook():
    # GitHub odesílá: X-Hub-Signature-256: sha256=<hex_digest>
    sig_header = request.headers.get("X-Hub-Signature-256", "")

    if not sig_header.startswith("sha256="):
        abort(403, "Missing or malformed signature header")

    received_hex = sig_header[len("sha256="):]
    raw_body = request.get_data()  # surové bajty — neparsujte JSON před tímto

    expected_hex = hmac.new(
        GITHUB_WEBHOOK_SECRET, raw_body, hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected_hex, received_hex):
        abort(403, "Signature mismatch — payload may have been tampered with")

    event_type = request.headers.get("X-GitHub-Event", "unknown")
    payload = request.get_json()
    print(f"Verified GitHub {event_type} event: {payload.get('action', '')}")
    return "", 200

Stejný vzor platí pro Shopify (X-Shopify-Hmac-SHA256) a Twilio (X-Twilio-Signature), s jediným rozdílem v názvu hlavičky a v tom, zda je podpis hex nebo Base64-enkódovaný. Vždy zkontrolujte dokumentaci poskytovatele pro potvrzení formátu kódování — záměna hex a Base64 je nejčastější příčinou chyb neshody podpisů.

Autentizace API požadavků pomocí HMAC

Některá API vyžadují, aby klient podepsal každý požadavek pomocí HMAC. Podpisový řetězec obvykle zahrnuje HTTP metodu, cestu, časové razítko a tělo požadavku. Zde je vzor, který používám pro interní autentizaci služba-ke-službě.

Python 3.7+ — podepisování API požadavků pomocí HMAC-SHA256
import hmac
import hashlib
import time
import json

def sign_request(secret: bytes, method: str, path: str, body: str) -> dict:
    """Vygeneruje HMAC-SHA256 podpis pro API požadavek."""
    timestamp = str(int(time.time()))

    # Sestavení podpisového řetězce — metoda + cesta + časové razítko + tělo
    signing_string = f"{method}\n{path}\n{timestamp}\n{body}"

    signature = hmac.new(
        secret,
        signing_string.encode(),
        hashlib.sha256
    ).hexdigest()

    return {
        "X-Timestamp": timestamp,
        "X-Signature": signature,
    }

# Použití
api_secret = b"sk_hmac_9f3a2b7c4d8e1a6f"
body = json.dumps({"customer_id": "cust_4421", "action": "suspend_account"})

headers = sign_request(api_secret, "POST", "/api/v2/customers/actions", body)
print(headers)
# {"X-Timestamp": "1711612200", "X-Signature": "a3f1b9c0..."}

Podepisování HTTP požadavků s knihovnou requests

Python 3.7+ — HMAC podepsané požadavky s knihovnou requests
import hmac
import hashlib
import time
import json
import requests

API_SECRET = b"sk_hmac_9f3a2b7c4d8e1a6f"
BASE_URL = "https://api.billing-service.internal"

def make_signed_request(method: str, path: str, payload: dict) -> requests.Response:
    body = json.dumps(payload, separators=(",", ":"))  # kompaktní JSON, deterministický
    timestamp = str(int(time.time()))

    signing_string = f"{method}\n{path}\n{timestamp}\n{body}"
    signature = hmac.new(API_SECRET, signing_string.encode(), hashlib.sha256).hexdigest()

    headers = {
        "Content-Type": "application/json",
        "X-Timestamp": timestamp,
        "X-Signature": f"hmac-sha256={signature}",
    }

    try:
        return requests.request(method, f"{BASE_URL}{path}", data=body, headers=headers)
    except requests.RequestException as e:
        raise RuntimeError(f"Signed request failed: {e}") from e

# Odeslání podepsaného POST požadavku
resp = make_signed_request("POST", "/api/v2/invoices", {
    "customer_id": "cust_4421",
    "line_items": [
        {"description": "Pro plan - March 2026", "amount": 4900},
        {"description": "Extra seats (3)", "amount": 2100},
    ],
})
print(resp.status_code, resp.json())

Poznámka: při serializaci těla pro podepisování použijte separators=(",", ":"). Výchozí json.dumps() přidává mezery za oddělovači, což mění bajtovou reprezentaci a narušuje ověření podpisu, pokud server serializuje jinak. Kompaktní JSON vám dává kanonický formát.

Generování HMAC z příkazové řádky

Někdy potřebujete vypočítat HMAC bez psaní skriptu. Přepínač -c Pythonu a openssl to zvládnou z terminálu.

bash — HMAC-SHA256 přes Python one-liner
python3 -c "
import hmac, hashlib
print(hmac.new(b'my_secret', b'message_to_sign', hashlib.sha256).hexdigest())
"
# výstup: 64znakový hex řetězec
bash — HMAC-SHA256 přes openssl (pro srovnání)
echo -n "message_to_sign" | openssl dgst -sha256 -hmac "my_secret"
# SHA2-256(stdin)= 7d11...

# Přesměrování souboru přes openssl HMAC
openssl dgst -sha256 -hmac "my_secret" < payload.json
bash — HMAC z proměnné prostředí
# Uložte klíč do proměnné prostředí, abyste předešli jeho zobrazení v historii shellu
export HMAC_KEY="sk_live_9f3a2b"
echo -n '{"event":"test"}' | python3 -c "
import hmac, hashlib, sys, os
key = os.environ['HMAC_KEY'].encode()
msg = sys.stdin.buffer.read()
print(hmac.new(key, msg, hashlib.sha256).hexdigest())
"
Poznámka:Přepínač echo -n je klíčový — bez něj echo přidá na konec zprávy znak nového řádku, což změní výstup HMAC. Toto je nejčastější příčina neshody podpisů při ladění z terminálu.

Výkonná alternativa — knihovna cryptography

Pro většinu aplikací je standardní modul hmac dostatečně rychlý. Pokud již používáte knihovnu cryptography pro TLS nebo práci s certifikáty, nabízí také HMAC podpořený OpenSSL. Hlavní praktický rozdíl od stdlib je výjimkové API .verify() popsané níže — při neshodě vyvolá výjimku místo vrácení booleanu, který byste mohli zapomenout zkontrolovat.

bash — instalace cryptography
pip install cryptography
Python 3.7+ — HMAC přes knihovnu cryptography
from cryptography.hazmat.primitives import hashes, hmac as crypto_hmac

key = b"webhook_signing_key_2026"
message = b'{"event":"subscription.renewed","plan":"enterprise"}'

h = crypto_hmac.HMAC(key, hashes.SHA256())
h.update(message)
signature = h.finalize()  # surové bajty

print(signature.hex())
# "9c4e2a..."

# Režim ověření — vyvolá InvalidSignature při neshodě
h_verify = crypto_hmac.HMAC(key, hashes.SHA256())
h_verify.update(message)
h_verify.verify(signature)  # vyvolá cryptography.exceptions.InvalidSignature, pokud je špatný

Metoda .verify() knihovny cryptography je obzvláště praktická: při neshodě vyvolá výjimku místo vrácení booleanu. Díky tomu je obtížnější neúmyslně ignorovat selhání ověření. Standardní hmac.compare_digest() vrací True/ False, což může být tiše ignorováno, pokud vývojář zapomene zkontrolovat návratovou hodnotu.

Výstup v terminálu se zvýrazňováním syntaxe

Pokud ladíte HMAC podpisy v terminálu a chcete barevný výstup, rich to zvládá dobře.

bash — instalace rich
pip install rich
Python 3.7+ — barevný výstup HMAC s rich
import hmac
import hashlib
from rich.console import Console
from rich.table import Table

console = Console()

key = b"debug_signing_key"
messages = {
    "/api/v2/orders": b'{"status":"active"}',
    "/api/v2/invoices": b'{"status":"pending"}',
    "/api/v2/customers": b'{"status":"verified"}',
}

table = Table(title="HMAC-SHA256 Signatures")
table.add_column("Endpoint", style="cyan")
table.add_column("Signature (první 32 znaků)", style="green")

for endpoint, body in messages.items():
    sig = hmac.new(key, body, hashlib.sha256).hexdigest()
    table.add_row(endpoint, sig[:32] + "...")

console.print(table)
Poznámka:Rich je pouze pro zobrazení v terminálu. Nepoužívejte ho při zápisu HMAC podpisů do souborů, HTTP hlaviček nebo systémů pro agregaci logů — ANSI escape kódy naruší výstup.

Práce s velkými soubory — inkrementální HMAC

U souborů nad 50 MB nebo tak je plýtvání načítat vše do paměti jen pro výpočet HMAC. Metoda .update() na objektu HMAC vám umožňuje předávat data po blocích. Díky tomu je využití paměti konstantní bez ohledu na velikost souboru.

Python 3.7+ — HMAC velkého souboru po blocích
import hmac
import hashlib

def hmac_file(key: bytes, filepath: str, chunk_size: int = 8192) -> str:
    """Vypočítá HMAC-SHA256 souboru bez načtení celého souboru do paměti."""
    h = hmac.new(key, digestmod=hashlib.sha256)

    try:
        with open(filepath, "rb") as f:
            while True:
                chunk = f.read(chunk_size)
                if not chunk:
                    break
                h.update(chunk)
    except OSError as e:
        raise OSError(f"Cannot read file '{filepath}': {e}") from e

    return h.hexdigest()

# Podpis 2 GB exportu databáze
signing_key = b"backup_integrity_key_2026"
signature = hmac_file(signing_key, "/var/backups/db-export-2026-03.sql.gz")
print(f"HMAC-SHA256: {signature}")
Python 3.7+ — ověření HMAC podpisu staženého souboru
import hmac
import hashlib

def verify_file_hmac(key: bytes, filepath: str, expected_hex: str) -> bool:
    """Ověří HMAC-SHA256 podpis souboru."""
    h = hmac.new(key, digestmod=hashlib.sha256)

    with open(filepath, "rb") as f:
        for chunk in iter(lambda: f.read(65536), b""):
            h.update(chunk)

    return hmac.compare_digest(h.hexdigest(), expected_hex)

# Ověření staženého artefaktu
is_valid = verify_file_hmac(
    key=b"release_signing_key",
    filepath="/tmp/release-v3.2.0.tar.gz",
    expected_hex="8e3a1f9b2c4d6e7f0a1b3c5d7e9f0a2b4c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f",
)
print(f"Integrita souboru: {'platná' if is_valid else 'POŠKOZENA'}")
Poznámka:Přejděte na blokový HMAC, když soubor překročí 50–100 MB nebo při zpracování nahrávek na webovém serveru, kde záleží na paměti pro každý požadavek. Přístup s .update() využívá pevnou paměť o velikosti chunk_size bez ohledu na velikost souboru. Výchozích 64 KB bloků je dostatečně velké pro amortizaci režie systémových volání a dostatečně malé, aby zůstalo v L2 cache na většině hardwaru.

Generování kryptograficky bezpečného HMAC klíče v Pythonu

Slabý nebo předvídatelný klíč podkopává celou konstrukci HMAC. Modul secrets (Python 3.6+) poskytuje kryptograficky silné náhodné bajty. Pro HMAC-SHA256 použijte 32bajtový klíč. Pro HMAC-SHA512 použijte 64 bajtů. Tyto hodnoty odpovídají velikosti interního bloku příslušných hashovacích algoritmů, což je optimální délka klíče podle RFC 2104.

Python 3.7+ — generování HMAC klíčů pomocí secrets
import secrets

# Generování klíčů odpovídajících velikosti bloku hashovacího algoritmu
sha256_key = secrets.token_bytes(32)   # 256 bitů — pro HMAC-SHA256
sha512_key = secrets.token_bytes(64)   # 512 bitů — pro HMAC-SHA512

# Hex reprezentace — bezpečná pro konfigurační soubory a proměnné prostředí
print(f"HMAC-SHA256 key: {sha256_key.hex()}")
# např. "a3f1b9c04e7d2f8a1b3c5d7e9f0a2b4c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f"

print(f"HMAC-SHA512 key: {sha512_key.hex()}")
# 128znakový hex řetězec

# URL-safe Base64 — kompaktní, bezpečné pro HTTP hlavičky
import base64
b64_key = base64.urlsafe_b64encode(sha256_key).decode("ascii")
print(f"Base64 key: {b64_key}")
# např. "o_G5wE59L4obPF1-nwortG2ODwobPExdXnqLnA0dLi8="
Varování:Nikdy nepoužívejte random.random() ani random.randbytes() z modulu random pro HMAC klíče. Výchozí modul random používá PRNG Mersenne Twister, který je předvídatelný po pozorování 624 výstupů. Pro bezpečnostně citlivou náhodnost vždy používejte secrets.token_bytes().

Délka klíče a požadavky RFC 2104

RFC 2104 specifikuje, že klíč HMAC může mít libovolnou délku, ale doporučuje klíč alespoň L bajtů — kde L je délka výstupu použité hashovací funkce. Pro HMAC-SHA256 je to 32 bajtů (256 bitů). Klíče kratší než L bitů proporcionálně snižují bezpečnostní rezervu. Klíče delší než velikost bloku hashe (64 bajtů pro SHA-256, 128 bajtů pro SHA-512) jsou nejprve zahashují na velikost bloku, takže použití klíčů delších než velikost bloku nepřináší žádnou výhodu. Držte se 32 bajtů pro HMAC-SHA256 a 64 bajtů pro HMAC-SHA512.

Bezpečné ukládání a rotace klíčů

Nikdy nezakódovávejte HMAC klíče pevně do zdrojového kódu. Standardní přístup pro produkční nasazení je načtení klíče z proměnné prostředí při spuštění: os.environ["HMAC_SECRET"].encode(). Pro prostředí s vyššími bezpečnostními požadavky uchovávejte klíče v systému pro správu tajemství, jako je AWS Secrets Manager, HashiCorp Vault nebo GCP Secret Manager, a načítejte je za běhu. Tyto systémy poskytují auditní záznamy, řízení přístupu a automatickou rotaci bez nutnosti nasazovat nový kód.

Plánujte rotaci klíčů od začátku. Při rotaci klíče existuje okno, kdy průběžné požadavky byly podepsány starým klíčem a selžou při ověření novým. Standardním řešením je krátké překryvné období: přijímejte podpisy jak od starého, tak od nového klíče po krátkou dobu (minuty až hodiny), poté starý klíč vyřaďte. Pokud je klíč kompromitován — byl odhalen v logu, unikl přes git commit nebo byl prozrazen při incidentu — okamžitě ho rotujte a všechny podpisy vytvořené kompromitovaným klíčem považujte za nedůvěryhodné. Znovu ověřte veškeré uložené výsledky ověření a informujte koncové odběratele o změně klíče.

Použití bytearray a memoryview s hmac.new()

Funkce hmac.new() přijímá libovolný objekt podobný bajtům pro parametry key i msg. To znamená, že můžete předat bytes, bytearray nebo memoryview přímo bez kopírování nebo konverze. Nejvíce na tom záleží ve dvou scénářích: implementace síťových protokolů, kde socket.recv_into() zapisuje data do předem alokovaného bufferu bytearray, a vysoce výkonné systémy, kde vyhýbání se mezikopíím snižuje tlak na garbage collector. Výřez memoryview je zero-copy: zpřístupňuje okno do původního bufferu bez přidělování nové paměti. Při desítkách tisíc zpráv za sekundu eliminace těchto přidělení paměti způsobuje měřitelný rozdíl v latenci a propustnosti.

Python 3.7+ — bytearray a memoryview s HMAC
import hmac
import hashlib

# bytearray — proměnlivé bajty, užitečné pro buffery binárních protokolů
key = bytearray(b"protocol_signing_key")
frame = bytearray(b'\x01\x02\x03\x04payload_data_here')

sig = hmac.new(key, frame, hashlib.sha256).hexdigest()
print(f"Frame signature: {sig[:32]}...")

# memoryview — zero-copy výřez většího bufferu
large_buffer = bytearray(4096)
large_buffer[:20] = b"sensor_reading_12345"

# HMAC pouze prvních 20 bajtů bez kopírování
view = memoryview(large_buffer)[:20]
sig = hmac.new(key, view, hashlib.sha256).hexdigest()
print(f"Sensor signature: {sig[:32]}...")

Časté chyby

První dvě chyby vidím téměř v každém code review zahrnujícím handlery webhooků. Je snadné je udělat pod časovým tlakem a těžké odhalit bez vědomí, co hledat.

Porovnávání HMAC podpisů pomocí == místo hmac.compare_digest()

Problém: Operátor == zkratuje při prvním neshodném bajtu a prozrazuje časové informace, které útočníkovi umožňují inkrementálně rekonstruovat očekávaný podpis.

Řešení: Pro porovnávání podpisů vždy používejte hmac.compare_digest() — běží v konstantním čase bez ohledu na to, kde k neshodě dojde.

Before · Python
After · Python
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()

if received_sig == expected_sig:  # ZRANITELNÉ vůči časovacímu útoku
    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):  # konstantní čas
    process_webhook(body)
Předávání řetězce místo bajtů do hmac.new()

Problém: hmac.new() vyžaduje objekty podobné bajtům. Předání Python str vyvolá TypeError: "key: expected bytes or bytearray, but got 'str'".

Řešení: Před předáním do hmac.new() zavolejte .encode() na řetězcové klíče a zprávy.

Before · Python
After · Python
key = "my_api_secret"  # str, nikoli bytes
msg = '{"event":"test"}'  # str, nikoli bytes
sig = hmac.new(key, msg, hashlib.sha256)  # TypeError!
key = "my_api_secret"
msg = '{"event":"test"}'
sig = hmac.new(key.encode(), msg.encode(), hashlib.sha256)
Zapomenutí digestmod (Python 3.4+)

Problém: Volání hmac.new(key, msg) bez třetího argumentu vyvolá TypeError. Před Pythonem 3.4 byl výchozí hodnotou MD5, ale tato výchozí hodnota byla z bezpečnostních důvodů odstraněna.

Řešení: Vždy předávejte algoritmus explicitně: hashlib.sha256, hashlib.sha512 nebo cokoli, co váš protokol vyžaduje.

Before · Python
After · Python
# Chybí digestmod — vyvolá TypeError v Pythonu 3.4+
sig = hmac.new(key, msg).hexdigest()
# Vždy specifikujte hashovací algoritmus
sig = hmac.new(key, msg, hashlib.sha256).hexdigest()
Použití .hexdigest() když poskytovatel očekává Base64

Problém: Mnoho poskytovatelů webhooků (Stripe, Shopify) odesílá Base64-enkódované podpisy, nikoli hex. Porovnávání hex řetězce s Base64 hodnotou vždy selže a všechny webhooky budou odmítnuty.

Řešení: Zkontrolujte dokumentaci poskytovatele pro formát podpisu. Pokud používají Base64, enkódujte surové bajty .digest(), nikoli řetězec .hexdigest().

Before · Python
After · Python
# Poskytovatel odesílá Base64, ale my počítáme hex — nikdy se neshoduje
expected = hmac.new(key, body, hashlib.sha256).hexdigest()
# "a3f1b9c0..."  vs  "o/G5wE59..."  — vždy neshoda
import base64
# Odpovídáme formátu poskytovatele: surové bajty → Base64
raw = hmac.new(key, body, hashlib.sha256).digest()
expected = base64.b64encode(raw).decode("ascii")
# "o/G5wE59..."  — odpovídá hlavičce

stdlib hmac vs cryptography — rychlé srovnání

Metoda
Algoritmus
Výstup
Proudové zpracování
Vlastní typy
Vyžaduje instalaci
hmac.new() + hexdigest()
Libovolný hashlib
Hex řetězec
✓ přes .update()
N/A
Ne (stdlib)
hmac.new() + digest()
Libovolný hashlib
Surové bajty
✓ přes .update()
N/A
Ne (stdlib)
hmac.digest()
Libovolný hashlib
Surové bajty
✗ (jednorázové)
N/A
Ne (stdlib, 3.7+)
hashlib.sha256 (prostý hash)
Pouze SHA-256
Hex nebo bajty
✓ přes .update()
N/A
Ne (stdlib)
cryptography (HMAC)
Libovolný
Surové bajty
✓ přes .update()
N/A
pip install
pyca/cryptography + CMAC
AES-CMAC
Surové bajty
✓ přes .update()
N/A
pip install

Pro ověřování webhooků, podepisování API a obecné operace HMAC používejte modul hmac ze stdlib — nevyžaduje žádné závislosti a pokrývá každý standardní algoritmus. Pro dávkové operace, kde záleží na rychlosti jednorázového výpočtu, použijte hmac.digest(). Sáhněte po knihovně cryptography pouze pokud na ní již závisíte kvůli jiným operacím (TLS, X.509, symetrické šifrování) a chcete výjimkové API .verify(). Pro rychlé kontroly podpisů bez psaní Pythonu použijte nástroj HMAC Generator — vložte klíč a zprávu a okamžitě získejte výsledek.

Často kladené otázky

Jaký je rozdíl mezi hmac.new() a hmac.digest() v Pythonu?

hmac.new() vrací objekt HMAC, který podporuje inkrementální volání .update() a poskytuje jak .digest() (surové bajty), tak .hexdigest() (hex řetězec). hmac.digest() je jednorázová funkce přidaná v Pythonu 3.7, která vrací surové bajty přímo bez vytváření meziobjektu. Použijte hmac.digest(), když máte celou zprávu a potřebujete pouze výsledek. Použijte hmac.new(), když potřebujete předávat data po blocích nebo potřebujete hex výstup.

Python
import hmac, hashlib

key = b"webhook_secret_2026"
body = b'{"event":"payment.completed","amount":9950}'

# Jednorázové — vrátí surové bajty
raw = hmac.digest(key, body, hashlib.sha256)

# Objektové — podporuje inkrementální aktualizace a hex výstup
h = hmac.new(key, body, hashlib.sha256)
hex_sig = h.hexdigest()

Jak ověřit HMAC podpis v Pythonu?

Přepočítejte HMAC nad původní zprávou pomocí sdíleného tajemství, poté porovnejte pomocí hmac.compare_digest(). Nikdy nepoužívejte == pro porovnání podpisů. Operátor == je zranitelný vůči časovacím útokům, protože zkratuje při prvním neshodném bajtu a prozrazuje informace o délce a obsahu očekávaného podpisu.

Python
import hmac, hashlib

def verify_signature(secret: bytes, message: bytes, received_sig: str) -> bool:
    expected = hmac.new(secret, message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received_sig)

Je Python HMAC SHA-256 totéž co hashování pomocí hashlib.sha256?

Ne. hashlib.sha256 vypočítá prostý SHA-256 hash vstupu, který může kdokoli reprodukovat. HMAC-SHA256 zapracovává tajný klíč do výpočtu hashe podle RFC 2104, takže pouze ten, kdo má klíč, může vytvořit nebo ověřit správný výstup. Prostý hash dokazuje integritu dat. HMAC dokazuje jak integritu, tak autentičnost.

Python
import hmac, hashlib

msg = b"transfer:9950:USD"
key = b"api_secret_k8x2"

plain_hash = hashlib.sha256(msg).hexdigest()  # kdokoli to může vypočítat
hmac_hash = hmac.new(key, msg, hashlib.sha256).hexdigest()  # vyžaduje klíč

Mohu použít HMAC-SHA1 v Pythonu 3?

Ano, předejte hashlib.sha1 jako argument digestmod. HMAC-SHA1 v Pythonu 3 stále funguje a modul hmac pro něj nevykazuje žádná varování o zastarání. SHA-1 je však považován za slabý pro nové návrhy — jeho odolnost vůči kolizím je nižší než 80 bitů a NIST ho v roce 2015 přestal doporučovat pro většinu použití digitálních podpisů. Hlavním důvodem pro použití HMAC-SHA1 dnes je zpětná kompatibilita s existujícími protokoly, které ho vyžadují, jako OAuth 1.0a nebo určité starší systémy webhooků. Pokud kontrolujete obě strany integrace, pro veškerou novou práci upřednostněte HMAC-SHA256 nebo HMAC-SHA512.

Python
import hmac, hashlib

key = b"oauth_consumer_secret"
base_string = b"GET&https%3A%2F%2Fapi.example.com&oauth_nonce%3Dabc123"
sig = hmac.new(key, base_string, hashlib.sha1).digest()

Jak vygenerovat bezpečný HMAC klíč v Pythonu?

Použijte secrets.token_bytes() ze standardní knihovny. Pro HMAC-SHA256 je standardním doporučením 32bajtový klíč, protože odpovídá velikosti bloku hashe. Pro HMAC-SHA512 použijte 64 bajtů. Nepoužívejte random.random() ani os.urandom() pro generování klíčů v aplikačním kódu — secrets je správný modul pro bezpečnostně citlivou náhodnost od Pythonu 3.6.

Python
import secrets

hmac_sha256_key = secrets.token_bytes(32)  # 256 bitů
hmac_sha512_key = secrets.token_bytes(64)  # 512 bitů

# Uložení jako hex pro konfigurační soubory
print(hmac_sha256_key.hex())
# např. "a3f1b9c04e..."

Proč hmac.new() vyžaduje digestmod v Pythonu 3?

Před Pythonem 3.4 byl digestmod výchozí hodnotou MD5, který je kryptograficky prolomen — MD5 má známé kolizní útoky a nikdy by neměl být používán v novém bezpečnostně citlivém kódu. Správci Pythonu výchozí hodnotu odstranili, aby vynutili explicitní volbu algoritmu a zabránili vývojářům tiše odesílat MACs založené na MD5. Pokud zavoláte hmac.new(key, msg) bez digestmod, dostanete TypeError. Vždy předávejte algoritmus explicitně: hashlib.sha256, hashlib.sha512 nebo jiný konstruktor hashlib. Pokud si nejste jisti, hashlib.sha256 je bezpečnou výchozí volbou — žádné známé slabiny a dostatečně rychlý pro jakoukoli praktickou zátěž.

Python
import hmac, hashlib

key = b"secret"
msg = b"data"

# Toto vyvolá TypeError v Pythonu 3.4+
# hmac.new(key, msg)  # TypeError: missing required argument: 'digestmod'

# Vždy specifikujte algoritmus
h = hmac.new(key, msg, hashlib.sha256)

Pro rychlou kontrolu HMAC bez spouštění Python skriptu vložte klíč a zprávu do online generátoru HMAC — podporuje SHA-256, SHA-384 a SHA-512 s okamžitými výsledky.

Související nástroje

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 SantosTechnický recenzent

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.