Python HMAC — hmac.new() SHA-256 Rehberi + Kod Örnekleri
Ücretsiz HMAC Üreticisi aracını doğrudan tarayıcınızda kullanın — kurulum gerektirmez.
HMAC Üreticisi Online Dene →Her webhook geri çağrısı, her imzalı API isteği, her Stripe veya GitHub olay bildirimi, yükün değiştirilmediğini kanıtlamak için bir HMAC imzası kullanır. Python'un hmac modülü, Python'da HMAC-SHA256 işlemlerini tek bir işlev çağrısıyla halleder: hmac.new(key, msg, hashlib.sha256). pip kurulumu yok, C eklentisi yok, üçüncü taraf bağımlılığı yok. Kod yazmadan hızlı imza kontrolleri için çevrimiçi HMAC Üretici sonucu anında verir. Bu rehber hmac.new(), hmac.digest(), hmac.compare_digest(), Base64 kodlaması, webhook doğrulama, API istek imzalama ve SHA-1'den SHA-512'ye tüm hash algoritmalarını kapsar. Tüm örnekler Python 3.7+ hedeflidir.
- ✓hmac.new(key, msg, hashlib.sha256) standart giriş noktasıdır — key ve msg bytes olmalı, digestmod Python 3.4'ten itibaren zorunludur.
- ✓hmac.digest(key, msg, "sha256"), Python 3.7'de eklenen daha hızlı tek seferlik bir alternatiftir — ara nesne oluşturmadan ham bytes döndürür.
- ✓Zamanlama saldırılarını önlemek için imzaları her zaman hmac.compare_digest() ile doğrulayın — HMAC karşılaştırması için asla == kullanmayın.
- ✓HTTP başlıkları ve webhook imzaları için ham .digest() çıktısını Base64'e kodlayın: base64.b64encode(h.digest()).
- ✓hmac modülü tüm hashlib algoritmalarını kabul eder: sha1, sha256, sha384, sha512, md5, blake2b.
HMAC Nedir?
HMAC (Hash Tabanlı Mesaj Doğrulama Kodu), RFC 2104 ile tanımlanan ve sabit boyutlu bir doğrulama etiketi üretmek için bir gizli anahtarı hash işleviyle birleştiren bir yapıdır. Herkesin hesaplayabileceği düz bir hashin aksine, HMAC gizli anahtarın bilinmesini gerektirir. Bu sayede bir mesajın hem bütünlüğünü hem de özgünlüğünü doğrulamak için kullanılabilir. Mesajın veya anahtarın tek bir byte'ı bile değişse çıktı tamamen farklı olur. Yapı, anahtarı iki farklı dolgu sabitiyle (ipad ve opad) XOR'layarak ve mesajı iki hash işlemi arasına sararak çalışır. Python'un hmac modülü bu RFC'yi doğrudan uygular.
# Düz SHA-256 karması — gizli anahtar yok, herkes hesaplayabilir hashlib.sha256(b"payment:9950:USD").hexdigest() # "7a3b1c..." (deterministik, herkese açık)
# HMAC-SHA256 — üretmek için gizli anahtar gerekir hmac.new(b"api_secret", b"payment:9950:USD", hashlib.sha256).hexdigest() # "e4f2a8..." (yalnızca anahtar sahibi hesaplayabilir)
hmac.new() — Standart Kütüphane Giriş Noktası
hmac modülü Python standart kütüphanesinin bir parçasıdır. İki import ile hazırsınız: import hmac, hashlib. Modüldeki üç ana işlev: hmac.new() (HMAC nesnesi oluşturur), hmac.digest() (tek seferlik, Python 3.7+) ve hmac.compare_digest() (sabit zamanlı karşılaştırma). pip kurulumu gerekmez.
hmac.new(key, msg, digestmod) üç argüman alır. Hem key hem de msg bytes benzeri nesneler olmalıdır ( bytes, bytearray veya memoryview). digestmod argümanı Python 3.4'ten itibaren zorunludur ve herhangi bir hashlib yapıcısını (örn. hashlib.sha256) veya "sha256" gibi bir dize adını kabul eder.
import hmac
import hashlib
key = b"webhook_signing_key_2026"
message = b'{"event":"invoice.paid","invoice_id":"inv_8f3a","amount":19900}'
# HMAC nesnesini oluştur ve hex imzasını al
signature = hmac.new(key, message, hashlib.sha256).hexdigest()
print(signature)
# "b4e74f6c9a1d3e5f8b2a7c0d4e6f1a3b5c7d9e0f2a4b6c8d0e1f3a5b7c9d0e2f"HMAC nesnesi iki çıktı yöntemi sunar. .digest() ham bytes döndürür (SHA-256 için 32 byte, SHA-512 için 64 byte). .hexdigest() ise küçük harfli bir hex dizesi döndürür. Hex dizesi sıradan bir Python str nesnesidir — kod çözme adımı gerekmez.
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 # İkisi aynı veriyi temsil eder — hex, bytes'ın dize kodlamasıdır assert raw_bytes.hex() == hex_string
Anahtarınız veya mesajınız bir Python dizesiyse, onu hmac.new()'e geçirmeden önce bytes'a dönüştürmek için .encode() çağırın. Bu, hemen hemen herkesin ilk seferinde tökezlediği bir noktadır — Python 3 dizeleri Unicode'dur, bytes değil; hmac modülü onları reddeder.
import hmac
import hashlib
# Dize anahtar ve mesaj — .encode() UTF-8 bytes'a dönüştürür
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..." — tutarlı hex dizesi çıktısıdigestmod parametresinin Python 3.4'ten itibaren varsayılan değeri yoktur. hmac.new(key, msg) çağrısı olmadan TypeError fırlatır. 3.4 öncesinde MD5'e varsayılan olarak ayarlıydı; Python geliştiricileri, sizi açık ve güvenli bir seçim yapmaya zorlamak için varsayılanı kaldırdı.HMAC-SHA256 Base64, SHA-1, SHA-512 ve MD5
hmac.new() işlevi, hashlib'de mevcut olan herhangi bir hash algoritmasıyla çalışır. Çoğu webhook sağlayıcısı ve API ağ geçidi HMAC-SHA256 kullanır; ancak OAuth 1.0a'da SHA-1, onu zorunlu kılan protokollerde SHA-512 ve henüz güncellenmemiş eski sistemlerde MD5 ile karşılaşacaksınız.
Base64 Çıktılı HMAC-SHA256
Birçok webhook sağlayıcısı imzayı bir HTTP başlığında Base64 kodlamalı dize olarak gönderir. Aynı biçimi üretmek için ham .digest() bytes'ını base64.b64encode()'a geçirin.
import hmac
import hashlib
import base64
key = b"whsec_MbkP7x9yFqHGn3tRdWz5"
payload = b'{"id":"evt_1Nq","type":"charge.succeeded","data":{"amount":4200}}'
# Ham özet → Base64 (Authorization başlıkları ve webhook imzaları için yaygın)
raw_digest = hmac.new(key, payload, hashlib.sha256).digest()
b64_signature = base64.b64encode(raw_digest).decode("ascii")
print(b64_signature)
# "dGhpcyBpcyBhIHNhbXBsZSBzaWduYXR1cmU="
# X-Signature başlığıyla karşılaştıracağınız değer budur
header_value = f"sha256={b64_signature}"
print(header_value)
# "sha256=dGhpcyBpcyBhIHNhbXBsZSBzaWduYXR1cmU="HMAC-SHA1 — Eski Protokol Uyumluluğu
SHA-1, yeni tasarımlar için zayıf kabul edilir; ancak HMAC-SHA1, OAuth 1.0a ve bazı eski webhook uygulamaları tarafından hâlâ gereklidir. Kod tamamen aynıdır — yalnızca algoritmayı değiştirin.
import hmac
import hashlib
consumer_secret = b"oauth_consumer_secret_2026"
token_secret = b"oauth_token_secret_2026"
# OAuth 1.0a imzalama anahtarı olarak consumer_secret&token_secret kullanır
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..." — Authorization başlığı için URL kodlaması yapınHMAC-SHA512 — Daha Uzun Çıktı
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 byte (512 bit)
print(len(h.hexdigest())) # 128 hex karakter
print(h.hexdigest()[:40] + "...")
# "8e3a1f9b2c4d6e7f0a1b3c5d7e9f0a2b4c6d8e0f..."HMAC-MD5 — Yalnızca Eski Sistemler
import hmac import hashlib # MD5 kriptografik açıdan kırılmıştır — yalnızca eski protokol uyumluluğu için kullanın key = b"legacy_api_key" msg = b"action=charge&amount=1500&merchant=store_42" sig = hmac.new(key, msg, hashlib.md5).hexdigest() print(sig) # 32 karakterli hex dizesi # "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
hmac.new() Parametre Referansı
Yapıcı imzası hmac.new(key, msg=None, digestmod)'dur. Modüldeki üç işlev de anahtar ve algoritma argümanları için aynı deseni paylaşır.
hmac.new() yapıcısı
hmac.digest() tek seferlik (Python 3.7+)
digestmod parametresi, bir callable (örn. hashlib.sha256) veya bir dize adı (örn. "sha256") kabul eder. Callable biçimi tercih edilir çünkü import zamanında doğrulanır — dize biçimindeki bir yazım hatası yalnızca çalışma zamanında başarısız olur.
hmac.digest() — Hızlı Tek Seferlik HMAC (Python 3.7+)
Python 3.7, hmac.digest(key, msg, digest)'i modül düzeyinde bir işlev olarak ekledi. Ara bir HMAC nesnesi oluşturmadan tek çağrıda HMAC hesaplar. Dönen değer ham bytes'tır (nesne üzerinde .digest() çağırmaya eşdeğer). Bu işlev, CPython'da optimize edilmiş bir C uygulaması kullanır ve nesne oluşturma yükünden kaçınır; bu da onu sıkı döngülerde ölçülebilir biçimde daha hızlı kılar.
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}',
]
# Tek seferlik özet — ara HMAC nesnesi yok
signatures = [hmac.digest(key, msg, hashlib.sha256) for msg in messages]
# Görüntülemek için hex'e dönüştür
for msg, sig in zip(messages, signatures):
print(f"{msg[:30]}... -> {sig.hex()[:24]}...")Sınırlama: hmac.digest() yalnızca ham bytes döndürür. Doğrudan hex dizesine ihtiyaç duyuyorsanız, yine de hmac.new()'in .hexdigest() yöntemine veya bytes sonucuna zincirlenen .hex()'e ihtiyacınız vardır.
hmac.digest() artımlı .update() çağrılarını desteklemez. Büyük bir dosyayı parçalar hâlinde okuyup içeriğini HMAC'lamak istiyorsanız hmac.new() kullanın ve bir döngüde .update(chunk) çağırın.Webhook ve API Yanıtından HMAC İmzası Doğrulama
Python'da HMAC'ın en yaygın kullanımı webhook imzalarını doğrulamaktır. Her büyük sağlayıcı (Stripe, GitHub, Shopify, Twilio) yükleri HMAC-SHA256 ile imzalar ve imzayı bir başlıkta gönderir. Desen her zaman aynıdır: ham istek gövdesi üzerinde HMAC'ı yeniden hesaplayın, ardından hmac.compare_digest() ile karşılaştırın.
Webhook İmzası Doğrulama
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():
# Ham gövdeyi al — imzalananla tam olarak eşleşmeli
raw_body = request.get_data()
# İmzayı başlıktan al
received_sig = request.headers.get("X-Signature-256", "")
# Ham gövde üzerinde HMAC'ı yeniden hesapla
expected_sig = hmac.new(WEBHOOK_SECRET, raw_body, hashlib.sha256).hexdigest()
# Sabit zamanlı karşılaştırma — zamanlama saldırılarını önler
if not hmac.compare_digest(f"sha256={expected_sig}", received_sig):
abort(403, "Geçersiz imza")
# İmza doğrulandı — olayı işle
event = request.get_json()
print(f"Doğrulanmış olay: {event['type']} için {event['data']['amount']}")
return "", 200hmac.compare_digest() işlevi iki dizeyi veya byte dizisini sabit zamanda karşılaştırır. Normal bir == karşılaştırması ilk uyuşmayan byte'ta kısa devre yapar. Bir saldırgan birçok istek üzerinde yanıt süresini ölçerek beklenen imzayı byte byte yeniden oluşturabilir. Sabit zamanlı karşılaştırma bu yan kanalı ortadan kaldırır.
GitHub Webhook Doğrulama
GitHub'un webhook biçimi tam deseni örnekler. Ham istek gövdesinin HMAC-SHA256'sını sha256= önekinin ardından hex olarak içeren bir X-Hub-Signature-256 başlığı gönderir; imzalama işlemi depo ayarlarınızda yapılandırdığınız webhook gizli anahtarıyla gerçekleştirilir. Genel webhook doğrulamadan temel fark, karşılaştırmadan önce sha256= önekini çıkarmanız ve istek gövdesinin ham bytes'larını okumanız gerektiğidir — önce JSON ayrıştırması yapmak byte gösterimini değiştirir ve doğrulamayı bozar.
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 şunu gönderir: X-Hub-Signature-256: sha256=<hex_digest>
sig_header = request.headers.get("X-Hub-Signature-256", "")
if not sig_header.startswith("sha256="):
abort(403, "Eksik veya hatalı biçimlendirilmiş imza başlığı")
received_hex = sig_header[len("sha256="):]
raw_body = request.get_data() # ham bytes — bundan önce JSON ayrıştırmayın
expected_hex = hmac.new(
GITHUB_WEBHOOK_SECRET, raw_body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected_hex, received_hex):
abort(403, "İmza uyuşmazlığı — yük değiştirilmiş olabilir")
event_type = request.headers.get("X-GitHub-Event", "unknown")
payload = request.get_json()
print(f"Doğrulanmış GitHub {event_type} olayı: {payload.get('action', '')}")
return "", 200Aynı desen Shopify (X-Shopify-Hmac-SHA256) ve Twilio (X-Twilio-Signature) için de geçerlidir; tek fark başlık adı ve imzanın hex mi yoksa Base64 mi olduğudur. Kodlama biçimini doğrulamak için her zaman sağlayıcı belgelerine bakın — hex ve Base64'ü karıştırmak imza uyuşmazlığı hatalarının en yaygın nedenidir.
HMAC ile API İsteği Kimlik Doğrulama
Bazı API'ler istemcinin her isteği HMAC ile imzalamasını gerektirir. İmzalanan dize genellikle HTTP yöntemini, yolu, zaman damgasını ve istek gövdesini içerir. Aşağıda dahili servisler arası kimlik doğrulama için kullandığım bir deseni bulabilirsiniz.
import hmac
import hashlib
import time
import json
def sign_request(secret: bytes, method: str, path: str, body: str) -> dict:
"""Bir API isteği için HMAC-SHA256 imzası oluştur."""
timestamp = str(int(time.time()))
# İmzalama dizesini oluştur — method + path + timestamp + body
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,
}
# Kullanım
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..."}requests Kütüphanesi ile HTTP İsteklerini İmzalama
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=(",", ":")) # kompakt JSON, deterministik
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"İmzalı istek başarısız: {e}") from e
# İmzalı bir POST isteği gönder
resp = make_signed_request("POST", "/api/v2/invoices", {
"customer_id": "cust_4421",
"line_items": [
{"description": "Pro plan - Mart 2026", "amount": 4900},
{"description": "Ekstra koltuklar (3)", "amount": 2100},
],
})
print(resp.status_code, resp.json())Hızlı not: gövdeyi imzalamak için serileştirirken separators=(",", ":") kullanın. Varsayılan json.dumps() ayraçlardan sonra boşluk ekler; bu da byte gösterimini değiştirir ve sunucu farklı serileştirme yapıyorsa imza doğrulamayı bozar. Kompakt JSON kanonik bir biçim sağlar.
Komut Satırından HMAC Oluşturma
Bazen bir betik yazmadan HMAC hesaplamanız gerekir. Python'un -c bayrağı ve openssl terminalden bunu halledebilir.
python3 -c " import hmac, hashlib print(hmac.new(b'my_secret', b'message_to_sign', hashlib.sha256).hexdigest()) " # çıktı: 64 karakterli hex dizesi
echo -n "message_to_sign" | openssl dgst -sha256 -hmac "my_secret" # SHA2-256(stdin)= 7d11... # Bir dosyayı openssl HMAC'tan geçir openssl dgst -sha256 -hmac "my_secret" < payload.json
# Shell geçmişinde açığa çıkmayı önlemek için anahtarı env değişkeninde saklayın
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 bayrağı kritik önemdedir — onsuz echo mesajın sonuna satır sonu karakteri ekler ve bu durum HMAC çıktısını değiştirir. Terminalden hata ayıklarken imza uyuşmazlığının en yaygın nedeni budur.Yüksek Performanslı Alternatif — cryptography Kütüphanesi
Çoğu uygulama için standart hmac modülü yeterince hızlıdır. TLS veya sertifika işlemleri için cryptography kütüphanesini zaten kullanıyorsanız, bu kütüphane de OpenSSL destekli HMAC sağlar. Stdlib'den temel pratik fark, aşağıda açıklanan istisna tabanlı .verify() API'sidir — uyuşmazlıkta boolean döndürmek yerine istisna fırlatır, bu sayede doğrulama hatalarını yanlışlıkla görmezden gelmek zorlaşır.
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() # ham bytes
print(signature.hex())
# "9c4e2a..."
# Doğrulama modu — uyuşmazlıkta InvalidSignature fırlatır
h_verify = crypto_hmac.HMAC(key, hashes.SHA256())
h_verify.update(message)
h_verify.verify(signature) # yanlışsa cryptography.exceptions.InvalidSignature fırlatırcryptography kütüphanesinin .verify() yöntemi özellikle kullanışlıdır: boolean döndürmek yerine uyuşmazlıkta istisna fırlatır. Bu, doğrulama hatasını yanlışlıkla görmezden gelmeyi zorlaştırır. Standart kütüphanenin hmac.compare_digest() işlevi True/ False döndürür; geliştirici dönüş değerini kontrol etmeyi unutursa sessizce görmezden gelinebilir.
Söz Dizimi Vurgulama ile Terminal Çıktısı
Terminalde HMAC imzalarını hata ayıklarken renkli çıktı istiyorsanız, rich bunu güzel bir şekilde halleder.
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 İmzaları")
table.add_column("Endpoint", style="cyan")
table.add_column("İmza (ilk 32 karakter)", 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)Büyük Dosyalarla Çalışma — Artımlı HMAC
50 MB ve üzeri dosyalar için yalnızca HMAC hesaplamak amacıyla her şeyi belleğe yüklemek gereksizdir. .update() yöntemi veriyi parçalar hâlinde beslemenizi sağlar. Bu yaklaşım bellek kullanımını dosya boyutundan bağımsız olarak sabit tutar.
import hmac
import hashlib
def hmac_file(key: bytes, filepath: str, chunk_size: int = 8192) -> str:
"""Dosyayı tamamen belleğe yüklemeden HMAC-SHA256 hesapla."""
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"'{filepath}' dosyası okunamıyor: {e}") from e
return h.hexdigest()
# 2 GB'lık bir veritabanı dışa aktarımını imzala
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:
"""Bir dosyanın HMAC-SHA256 imzasını doğrula."""
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)
# İndirilen bir artefaktı doğrula
is_valid = verify_file_hmac(
key=b"release_signing_key",
filepath="/tmp/release-v3.2.0.tar.gz",
expected_hex="8e3a1f9b2c4d6e7f0a1b3c5d7e9f0a2b4c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f",
)
print(f"Dosya bütünlüğü: {'geçerli' if is_valid else 'BOZUK'}").update() yaklaşımı dosya boyutundan bağımsız olarak sabit miktarda chunk_size belleği kullanır. Varsayılan olarak 64 KB parçaları tercih ederim — sistem çağrısı yükünü amorti etmeye yetecek kadar büyük, çoğu donanımda L2 önbellekte kalacak kadar küçük.Python'da Kriptografik Açıdan Güvenli HMAC Anahtarı Oluşturma
Zayıf veya tahmin edilebilir bir anahtar, HMAC yapısının tamamını zayıflatır. secrets modülü (Python 3.6+) kriptografik açıdan güçlü rastgele bytes sağlar. HMAC-SHA256 için 32 byte'lık anahtar kullanın. HMAC-SHA512 için 64 byte. Bunlar, RFC 2104'e göre optimal anahtar uzunluğu olan ilgili hash algoritmalarının dahili blok boyutuyla eşleşir.
import secrets
# Hash algoritmasının blok boyutuyla eşleşen anahtarlar oluştur
sha256_key = secrets.token_bytes(32) # 256 bit — HMAC-SHA256 için
sha512_key = secrets.token_bytes(64) # 512 bit — HMAC-SHA512 için
# Hex gösterimi — yapılandırma dosyaları ve ortam değişkenleri için güvenli
print(f"HMAC-SHA256 anahtarı: {sha256_key.hex()}")
# örn. "a3f1b9c04e7d2f8a1b3c5d7e9f0a2b4c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f"
print(f"HMAC-SHA512 anahtarı: {sha512_key.hex()}")
# 128 karakterli hex dizesi
# URL güvenli Base64 — kompakt, HTTP başlıkları için güvenli
import base64
b64_key = base64.urlsafe_b64encode(sha256_key).decode("ascii")
print(f"Base64 anahtar: {b64_key}")
# örn. "o_G5wE59L4obPF1-nwortG2ODwobPExdXnqLnA0dLi8="random modülündeki random.random() veya random.randbytes() kullanmayın. Varsayılan random modülü, 624 çıktı gözlemlendikten sonra tahmin edilebilen Mersenne Twister PRNG'yi kullanır. Güvenlik açısından hassas rastgelelik için her zaman secrets.token_bytes() kullanın.Anahtar Uzunluğu ve RFC 2104 Gereksinimleri
RFC 2104, HMAC anahtarının herhangi bir uzunlukta olabileceğini belirtir; ancak en az L byte'lık bir anahtar önerir — L, temel hash işlevinin çıktı uzunluğudur. HMAC-SHA256 için bu 32 byte'tır (256 bit). L bit'ten kısa anahtarlar güvenlik marjini orantılı olarak azaltır. Hash'in blok boyutundan (SHA-256 için 64 byte, SHA-512 için 128 byte) uzun anahtarlar önce blok boyutuna hash'lenir; dolayısıyla blok boyutundan daha uzun anahtar kullanmanın hiçbir faydası yoktur. HMAC-SHA256 için 32 byte, HMAC-SHA512 için 64 byte kullanın.
Güvenli Anahtar Depolama ve Rotasyon
HMAC anahtarlarını kaynak koduna asla sabit olarak yazmayın. Üretim dağıtımları için standart yaklaşım, anahtarı başlangıçta bir ortam değişkeninden yüklemektir: os.environ["HMAC_SECRET"].encode(). Daha yüksek güvence gerektiren ortamlar için anahtarları AWS Secrets Manager, HashiCorp Vault veya GCP Secret Manager gibi bir gizli bilgi yönetim sisteminde saklayın ve çalışma zamanında alın. Bu sistemler denetim günlükleri, erişim kontrolleri ve kod dağıtımı gerektirmeyen otomatik rotasyon sağlar.
Anahtar rotasyonunu baştan planlayın. Bir anahtar değiştirildiğinde, uçuştaki isteklerin eski anahtarla imzalandığı ve yeni anahtara karşı doğrulamada başarısız olacağı bir pencere oluşur. Standart çözüm kısa bir örtüşme dönemidir: hem eski hem yeni anahtardan gelen imzaları kısa bir süre (dakikalar ila saatler) kabul edin, ardından eski anahtarı devre dışı bırakın. Bir anahtar tehlikeye girerse — günlüklerde açığa çıktıysa, bir git commit'iyle sızdıysa veya bir olayda ifşa edildiyse — derhal döndürün ve ele geçirilen anahtarla üretilen tüm imzaları güvenilmez olarak değerlendirin. Önbelleğe alınmış doğrulama sonuçlarını yeniden doğrulayın ve anahtar değişikliği konusunda aşağı akış tüketicilerini bilgilendirin.
hmac.new() ile bytearray ve memoryview Kullanımı
hmac.new() işlevi, hem anahtar hem de msg parametreleri için herhangi bir bytes benzeri nesneyi kabul eder. Bu, kopyalama veya dönüştürme yapmadan doğrudan bytes, bytearray veya memoryview geçirebileceğiniz anlamına gelir. Bu durum en çok iki senaryoda önem taşır: socket.recv_into()'un veriyi önceden ayrılmış bir bytearray tamponuna yazdığı ağ protokolü uygulamaları ve ara kopyaların GC baskısını azalttığı yüksek verimli sistemler. Bir memoryview dilimi sıfır kopyaladır: yeni bellek ayırmadan orijinal tampon üzerinde bir pencere sunar. Saniyede on binlerce mesaj işlendiğinde bu ayırmaları ortadan kaldırmak gecikme ve verim üzerinde ölçülebilir bir fark yaratır.
import hmac
import hashlib
# bytearray — değiştirilebilir bytes, ikili protokol tamponları için kullanışlı
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"Çerçeve imzası: {sig[:32]}...")
# memoryview — daha büyük bir tamponun sıfır kopyalı dilimi
large_buffer = bytearray(4096)
large_buffer[:20] = b"sensor_reading_12345"
# Kopyalamadan yalnızca ilk 20 byte'ı HMAC'la
view = memoryview(large_buffer)[:20]
sig = hmac.new(key, view, hashlib.sha256).hexdigest()
print(f"Sensör imzası: {sig[:32]}...")Yaygın Hatalar
İlk iki hatayı, webhook işleyicilerini içeren neredeyse her kod incelemesinde görüyorum. Zaman baskısı altında kolayca yapılıyor ve ne arayacağınızı bilmeden fark etmek zor.
Sorun: == operatörü, ilk byte uyuşmazlığında kısa devre yaparak bir saldırganın beklenen imzayı adım adım yeniden oluşturmasına olanak tanıyan zamanlama bilgisi sızdırır.
Çözüm: İmza karşılaştırması için her zaman hmac.compare_digest() kullanın — uyuşmazlığın nerede oluştuğundan bağımsız olarak sabit zamanda çalışır.
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if received_sig == expected_sig: # zamanlama saldırısına AÇIK
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): # sabit zamanlı
process_webhook(body)Sorun: hmac.new() bytes benzeri nesneler gerektirir. Python str geçmek TypeError fırlatır: "key: expected bytes or bytearray, but got 'str'".
Çözüm: String anahtarlar ve mesajları hmac.new()'e geçirmeden önce .encode() çağırın.
key = "my_api_secret" # str, bytes değil
msg = '{"event":"test"}' # str, bytes değil
sig = hmac.new(key, msg, hashlib.sha256) # TypeError!key = "my_api_secret"
msg = '{"event":"test"}'
sig = hmac.new(key.encode(), msg.encode(), hashlib.sha256)Sorun: Üçüncü argüman olmadan hmac.new(key, msg) çağırmak TypeError fırlatır. Python 3.4 öncesinde varsayılan olarak MD5'ti; ancak güvenlik nedeniyle varsayılan kaldırıldı.
Çözüm: Algoritmayı her zaman açıkça belirtin: hashlib.sha256, hashlib.sha512 veya protokolünüzün gerektirdiği algoritma.
# Eksik digestmod — Python 3.4+'da TypeError fırlatır sig = hmac.new(key, msg).hexdigest()
# Hash algoritmasını her zaman belirtin sig = hmac.new(key, msg, hashlib.sha256).hexdigest()
Sorun: Birçok webhook sağlayıcısı (Stripe, Shopify) hex değil Base64 kodlamalı imzalar gönderir. Hex dizeyi Base64 değeriyle karşılaştırmak her zaman başarısız olur ve tüm webhook'lar reddedilir.
Çözüm: İmza biçimi için sağlayıcı belgelerine bakın. Base64 kullanıyorlarsa .hexdigest() dizesini değil ham .digest() bytes'ını kodlayın.
# Sağlayıcı Base64 gönderiyor, biz hex hesaplıyoruz — hiç eşleşmez expected = hmac.new(key, body, hashlib.sha256).hexdigest() # "a3f1b9c0..." vs "o/G5wE59..." — her zaman uyuşmazlık
import base64
# Sağlayıcının biçimiyle eşleştir: ham bytes → Base64
raw = hmac.new(key, body, hashlib.sha256).digest()
expected = base64.b64encode(raw).decode("ascii")
# "o/G5wE59..." — başlıkla eşleşirstdlib hmac ile cryptography Karşılaştırması
Webhook doğrulama, API imzalama ve genel HMAC işlemleri için stdlib hmac modülünü kullanın — sıfır bağımlılık gerektirir ve tüm standart algoritmaları kapsar. Tek seferlik hızın önemli olduğu toplu işlemler için hmac.digest() kullanın. cryptography kütüphanesine yalnızca diğer işlemler (TLS, X.509, simetrik şifreleme) için zaten bağımlılığınız varsa ve istisna tabanlı .verify() API'sini istiyorsanız başvurun. Herhangi bir Python kodu yazmadan hızlı imza kontrolleri için HMAC Üretici aracını kullanarak anahtarınızı ve mesajınızı yapıştırın, sonucu anında alın.
Sık Sorulan Sorular
Python'da hmac.new() ile hmac.digest() arasındaki fark nedir?
hmac.new(), artımlı .update() çağrılarını destekleyen ve hem .digest() (ham bytes) hem de .hexdigest() (hex dizesi) veren bir HMAC nesnesi döndürür. hmac.digest() ise Python 3.7'de eklenen, ara nesne oluşturmadan doğrudan ham bytes döndüren tek seferlik bir işlevdir. Mesajın tamamı elinizde olduğunda ve yalnızca sonuca ihtiyaç duyduğunuzda hmac.digest() kullanın. Veriyi parçalar hâlinde beslemek veya hex çıktısına ihtiyaç duyduğunuzda ise hmac.new() tercih edin.
import hmac, hashlib
key = b"webhook_secret_2026"
body = b'{"event":"payment.completed","amount":9950}'
# Tek seferlik — ham bytes döndürür
raw = hmac.digest(key, body, hashlib.sha256)
# Nesne tabanlı — artımlı güncellemeleri ve hex çıktısını destekler
h = hmac.new(key, body, hashlib.sha256)
hex_sig = h.hexdigest()Python'da HMAC imzası nasıl doğrulanır?
Orijinal mesaj üzerinde paylaşılan gizli anahtarı kullanarak HMAC'ı yeniden hesaplayın, ardından hmac.compare_digest() ile karşılaştırın. İmza karşılaştırması için asla == kullanmayın. == operatörü, ilk uyuşmayan byte'ta kısa devre yaparak beklenen imzanın uzunluğu ve içeriği hakkında bilgi sızdırır — bu da zamanlama saldırılarına kapı açar.
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)Python hmac SHA-256, hashlib.sha256 ile hashing yapmakla aynı şey midir?
Hayır. hashlib.sha256, herkesin hesaplayabileceği düz bir SHA-256 karması üretir. HMAC-SHA256 ise RFC 2104'e göre gizli anahtarı hash hesaplamasına karıştırır; dolayısıyla yalnızca anahtara sahip olan kişi doğru çıktıyı üretebilir veya doğrulayabilir. Düz bir hash yalnızca veri bütünlüğünü kanıtlar. HMAC ise hem bütünlüğü hem de özgünlüğü kanıtlar.
import hmac, hashlib msg = b"transfer:9950:USD" key = b"api_secret_k8x2" plain_hash = hashlib.sha256(msg).hexdigest() # herkes hesaplayabilir hmac_hash = hmac.new(key, msg, hashlib.sha256).hexdigest() # anahtarı gerektirir
Python 3'te HMAC-SHA1 kullanabilir miyim?
Evet, digestmod argümanı olarak hashlib.sha1 geçin. HMAC-SHA1, Python 3'te sorunsuz çalışır ve hmac modülü buna ilişkin herhangi bir kullanımdan kaldırma uyarısı vermez. Bununla birlikte, SHA-1 yeni tasarımlar için zayıf kabul edilir — çakışma direnci 80 bit altındadır ve NIST, 2015'te çoğu dijital imza kullanımı için SHA-1'i kullanımdan kaldırmıştır. Günümüzde HMAC-SHA1 kullanmanın temel nedeni, OAuth 1.0a veya belirli eski webhook sistemleri gibi onu zorunlu kılan mevcut protokollerle geriye dönük uyumluluktur. Entegrasyonun her iki tarafını da siz kontrol ediyorsanız, tüm yeni çalışmalar için HMAC-SHA256 veya HMAC-SHA512 tercih edin.
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()
Python'da güvenli bir HMAC anahtarı nasıl oluşturulur?
Standart kütüphanedeki secrets.token_bytes() işlevini kullanın. HMAC-SHA256 için standart öneri, hash blok boyutuyla eşleşen 32 byte'lık bir anahtardır. HMAC-SHA512 için 64 byte kullanın. Güvenlik açısından hassas rastgelelik gerektiren uygulama kodunda random.random() veya os.urandom() kullanmayın — Python 3.6'dan itibaren bu amaç için doğru modül secrets'tır.
import secrets hmac_sha256_key = secrets.token_bytes(32) # 256 bit hmac_sha512_key = secrets.token_bytes(64) # 512 bit # Yapılandırma dosyaları için hex gösterimi print(hmac_sha256_key.hex()) # örn. "a3f1b9c04e..."
Python 3'te hmac.new() neden digestmod gerektirir?
Python 3.4 öncesinde digestmod varsayılan olarak MD5'e ayarlıydı; ancak MD5 kriptografik açıdan kırılmış durumdadır — bilinen çakışma saldırıları mevcuttur ve yeni güvenlik açısından hassas kodlarda asla kullanılmamalıdır. Python geliştiricileri, açık bir algoritma seçimini zorunlu kılmak ve geliştiricilerin farkında olmadan MD5 tabanlı MAC'ler göndermesini önlemek için varsayılanı kaldırdı. digestmod olmadan hmac.new(key, msg) çağrısı TypeError fırlatır. Algoritmayı her zaman açıkça belirtin: hashlib.sha256, hashlib.sha512 veya başka bir hashlib yapıcısı. Şüphe durumunda hashlib.sha256 güvenli varsayılandır — bilinen bir zafiyeti yok ve her pratik iş yükü için yeterince hızlı.
import hmac, hashlib key = b"secret" msg = b"data" # Python 3.4+'da TypeError fırlatır # hmac.new(key, msg) # TypeError: missing required argument: 'digestmod' # Algoritmayı her zaman belirtin h = hmac.new(key, msg, hashlib.sha256)
Bir Python betiği çalıştırmadan hızlı HMAC kontrolü yapmak için anahtarınızı ve mesajınızı çevrimiçi HMAC Üretici'ye yapıştırın — SHA-256, SHA-384 ve SHA-512 desteğiyle anında sonuç verir.
İlgili Araçlar
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.