HMAC v Pythonu — průvodce hmac.new() SHA-256 + příklady kódu
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.
# 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".
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í.
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á.
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ýstupdigestmod 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().
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.
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 AuthorizationHMAC-SHA512 — delší výstup
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
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"
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()
hmac.digest() jednorázové (Python 3.7+)
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.
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ů.
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
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 "", 200Funkce 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í.
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 "", 200Stejný 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ě.
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
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.
python3 -c " import hmac, hashlib print(hmac.new(b'my_secret', b'message_to_sign', hashlib.sha256).hexdigest()) " # výstup: 64znakový hex řetězec
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
# 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())
"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.
pip install 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.
pip install 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)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.
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}")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'}").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.
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="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.
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.
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.
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)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.
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)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.
# 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()
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().
# 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čcestdlib hmac vs cryptography — rychlé srovnání
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.
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.
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.
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.
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.
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ěž.
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
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.