λ μ§: 2025-06-07
API μλ² κ°μ μμ ν ν΅μ μ΄λ μμ μΈμ¦μ΄ νμν λ μ¬μ©ν μ μλ HMAC κΈ°λ°μ κ°λ¨ν ν ν° μμ± λ‘μ§μ μκ°ν©λλ€.
μ΄ λ°©μμ ID + SECRET + TIMESTAMP μ‘°ν©μΌλ‘ μμ±λ ν ν°μ μ΄μ©νμ¬, μμ μΈ‘μμλ λμΌν μκ³ λ¦¬μ¦μΌλ‘ ν ν°μ κ²μ¦ν μ μμ΅λλ€.
auth_token.py
)# auth_token.py
import hmac
import hashlib
import time
class AuthToken:
def __init__(self, client_id: str, client_secret: str, hash_algo: str = 'sha256', valid_window: int = 3):
"""
μΈμ¦ ν ν° μμ±κΈ° μ΄κΈ°ν
Args:
client_id (str): ν΄λΌμ΄μΈνΈ μλ³μ (μ: 'my-client')
client_secret (str): ν΄λΌμ΄μΈνΈ λΉλ° ν€ (HMAC μλͺ
μ©)
hash_algo (str): μ¬μ©ν ν΄μ μκ³ λ¦¬μ¦ (κΈ°λ³Έκ°: 'sha256')
valid_window (int): ν ν° μ ν¨ μκ°(μ΄ λ¨μ, κΈ°λ³Έκ°: 3μ΄)
"""
self.client_id = client_id
self.secret_key = client_secret.encode()
self.hash_algo = getattr(hashlib, hash_algo)
self.valid_window = valid_window
def generate(self, timestamp: int = None) -> str:
if timestamp is None:
timestamp = int(time.time())
raw = f"{self.client_id}.{timestamp}"
signature = hmac.new(self.secret_key, raw.encode(), self.hash_algo).hexdigest()
return f"{self.client_id}:{timestamp}:{signature}"
def verify(self, token: str) -> bool:
try:
parts = token.split(":")
if len(parts) != 3:
return False
token_id, token_ts, token_sig = parts
if token_id != self.client_id:
return False
token_ts = int(token_ts)
now = int(time.time())
if abs(now - token_ts) > self.valid_window:
return False
expected_token = self.generate(token_ts)
return hmac.compare_digest(token, expected_token)
except Exception:
return False
from auth_token import AuthToken
auth = AuthToken(client_id="example-client", client_secret="shared_secret")
# 1. μλ²μμ ν ν° μμ±
token = auth.generate()
print("π Generated:", token)
# 2. λ€λ₯Έ μλ² λλ μμ μΈ‘μμ ν ν° κ²μ¦
is_valid = auth.verify(token)
print("β
Valid:", is_valid)
SECRET_KEY
κΈ°λ° HMAC ν ν°μΌλ‘ λ³μ‘° μν μ΅μνtimestamp
κΈ°λ° μ ν¨κΈ°κ° μ€μ μΌλ‘ μ¬μ¬μ© λ°©μ§hmac.compare_digest()
λ₯Ό μ¬μ©ν΄ νμ΄λ° 곡격 λ°©μ΄
X-Auth-Token
νμμΌλ‘ ν¬ν¨μν€λ©΄ μ’μ΅λλ€.client_id
+ secret_key
λ₯Ό 미리 λ±λ‘ν΄λκ³ κ²μ¦νλ λ°©μμΌλ‘ νμ₯ κ°λ₯ν©λλ€.μλ² κ° ν΅μ (μλ² β μλ²)
client_id
+ secret_key
κΈ°λ°μΌλ‘ ν ν°μ μμ±νκ³ κ²μ¦.λ΄λΆ API μΈμ¦ (곡κ°λμ§ μλ λ΄λΆ μμ€ν κ°)
3rd Party API μΈμ¦ (κ°λ¨ν API Key + μλͺ λ°©μ)
timestamp
+ path
+ params
λ₯Ό HMACμΌλ‘ μλͺ
ν ν€λμ ν¬ν¨Webhook μΈμ¦
client_secret
μ΄ λ
ΈμΆλλ©΄ λꡬλ μ§ μ ν¨ν ν ν°μ λ§λ€ μ μμtimestamp
+ nonce
μ¬μ©νκ±°λ, Redisλ‘ ν ν° 1ν μ¬μ© μ ν, ν ν° μ ν¨κΈ°κ°μ μ§§κ² μ€μ .νλͺ© | HMAC μΈμ¦ λ°©μμ νΉμ§ |
---|---|
μ₯μ | ꡬν κ°λ¨, μμ‘΄μ± μμ, λΉ λ¦, ν ν° μμ‘° λ°©μ§ |
λ¨μ | secret μ μΆ μ μν, νμ·¨ λ°©μ§ νμ, μμ μΈμ¦ μ΄λ €μ |
μ ν©ν κ²½μ° | μλ² κ° ν΅μ , λ΄λΆ API, μΉν 보μ λ± μ νλ μ λ’° νκ²½ |
κ°λ¨νμ§λ§ μμ ν μΈμ¦ κ΅¬μ‘°κ° νμν λ μ HMAC κΈ°λ° ν ν° λ°©μμ μ κ·Ή νμ©ν΄ 보μΈμ. μΆν νμ μ, IP μ ν, μμ² URL ν¬ν¨, Nonce μΆκ° λ±μΌλ‘ νμ₯λ κ°λ₯ν©λλ€.