Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

Keyed Hash (HMAC) ใน Python สำหรับ Message Authentication

HMAC (Hash-based Message Authentication Code) ใช้ยืนยัน Integrity และ Authenticity ของข้อความ ด้วย Secret Key และ Hash Function (MD5, SHA-1, SHA-256, etc.)

import hmac, import hashlib


หลักการทำงาน

HMAC(K, m) = H((K' ⊕ opad) || H((K' ⊕ ipad) || m))

  • K = Secret Key
  • m = Message
  • H = Hash Function
  • Key ถูก Pad/Truncate ให้เท่า Block Size

เมธอดหลักของ HMAC Object

  • hmac.new(key, msg=None, digestmod='') - สร้าง HMAC Object
  • update(data) - เพิ่มข้อมูล (เรียกซ้ำได้ = Concatenate)
  • digest() - คืน Binary Digest
  • hexdigest() - คืน Hex String (สะดวกส่งผ่าน Network)
  • copy() - คัดลอก Object (คำนวณต่อจากจุดเดิมได้)

โค้ดตัวอย่าง

import hmac
import hashlib

# ข้อมูลและ Key
message = b'Python123'
key = b'abcde1234'

# สร้าง HMAC-SHA256
h = hmac.new(key, message, hashlib.sha256)

print("Digest (bytes):", h.digest())
print("Hex Digest:", h.hexdigest())
print("Algorithm:", h.name)  # hmac-sha256

# Copy และคำนวณต่อ
h2 = h.copy()
h2.update(b' more data')
print("Extended:", h2.hexdigest())

# Verify HMAC (Constant-time Comparison)
received_mac = b'...'
expected_mac = h.digest()
if hmac.compare_digest(received_mac, expected_mac):
    print("Valid!")
else:
    print("Invalid!")

สำคัญ: hmac.compare_digest(a, b)

เปรียบเทียบแบบ Constant-Time ป้องกัน Timing Attack

# ❌ ไม่ปลอดภัย
if h.hexdigest() == received_hex: ...

# ✅ ปลอดภัย
if hmac.compare_digest(h.digest(), received_bytes): ...

กรณีใช้งานจริง

  • API Authentication: Sign Request Parameters
  • Webhook Verification: GitHub, Stripe, Slack ส่ง HMAC Signature
  • Cookie Signing: ป้องกัน Tampering
  • Password Reset Tokens: HMAC(user_id + timestamp, secret)
  • JWT Alternative: Simple Signed Payload

ตัวอย่าง: Verify Webhook Signature (GitHub Style)

import hmac, hashlib

def verify_webhook(payload, signature_header, secret):
    # signature_header = "sha256=abc123..."
    algo, received_sig = signature_header.split('=', 1)
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received_sig)

# Usage
if verify_webhook(request.body, request.headers['X-Hub-Signature-256'], WEBHOOK_SECRET):
    process_webhook()
else:
    abort(401, "Invalid signature")