웹훅 완벽 가이드: 서명된 페이로드와 재시도

Backend2026-10-24TryQuickToolBox

API를 구축했고 이제 이벤트가 발생할 때 다른 서비스에 알림을 보내야 합니다. 웹훅 엔드포인트를 설정했지만 HTTP 요청을 안정적으로 전달하는 것이 생각보다 어렵다는 것을 금방 깨닫게 됩니다. 네트워크 장애, 악의적인 공격자, 중복 이벤트로 인해 혼란이 발생할 수 있습니다. 이 가이드에서는 서명된 페이로드와 재시도를 사용하여 웹훅을 구현하는 방법을 설명하여 견고한 통합을 구축할 수 있도록 도와드립니다.

웹훅이란 무엇인가요?

웹훅은 사용자 정의 HTTP 콜백입니다. 애플리케이션에서 이벤트가 발생하면 구독자가 제공한 URL로 HTTP POST 요청을 보냅니다. 이를 통해 폴링 없이 서비스 간 실시간 통신이 가능합니다.

예를 들어 결제 처리기는 결제가 성공하면 앱에 웹훅을 보낼 수 있습니다. 그러면 앱은 즉시 주문 상태를 업데이트할 수 있습니다.

웹훅 페이로드에 서명하는 이유는 무엇인가요?

웹훅 엔드포인트는 공개적으로 접근 가능하므로 누구나 가짜 요청을 보낼 수 있습니다. 검증 없이는 앱이 사기 이벤트를 처리할 수 있습니다. 페이로드에 서명하면 요청이 서비스에서 시작되었고 변조되지 않았음을 보장할 수 있습니다.

서명은 일반적으로 발신자와 수신자 간에 공유된 비밀 키를 사용합니다. 발신자는 페이로드에 대해 해시 기반 메시지 인증 코드(HMAC)를 계산하고 헤더에 포함합니다. 수신자는 HMAC을 다시 계산하고 비교합니다.

서명 생성 및 검증 방법

대부분의 구현은 HMAC-SHA256을 사용합니다. 다음은 Python의 간단한 예입니다:

import hmac
import hashlib
import json

def generate_signature(payload, secret):
    body = json.dumps(payload, separators=(',', ':')).encode('utf-8')
    signature = hmac.new(secret.encode('utf-8'), body, hashlib.sha256).hexdigest()
    return signature

def verify_signature(payload, signature, secret):
    expected = generate_signature(payload, secret)
    return hmac.compare_digest(expected, signature)

웹훅을 보낼 때 X-Signature와 같은 헤더에 서명을 포함하세요. 수신자는 원시 본문을 추출하고 HMAC을 다시 계산하여 비교합니다. 타이밍 공격을 방지하려면 항상 상수 시간 비교 함수를 사용하세요.

안정적인 전달을 위한 재시도 구현

웹훅은 인터넷을 통해 전송되므로 실패는 불가피합니다. 서버가 다운되었거나 네트워크가 느리거나 구독자가 오류를 반환할 수 있습니다. 지수 백오프를 사용한 재시도가 필수적입니다.

재시도 전략

일반적인 접근 방식은 지연 시간을 늘려가며 재시도하는 것입니다: 1분, 5분, 30분, 2시간 등. 최대 시도 횟수(예: 10회) 또는 총 시간 창(예: 24시간) 후에 중지합니다.

특정 조건에서만 재시도하세요: 네트워크 오류, 5xx 응답 또는 429(너무 많은 요청). 4xx 오류(429 제외)는 재시도로 해결되지 않는 클라이언트 실수를 나타내므로 재시도하지 마세요.

재시도 로직 예제

다음은 requests 라이브러리를 사용한 Python의 간단한 재시도 메커니즘입니다:

import requests
import time
from requests.exceptions import RequestException

def send_webhook(url, payload, secret, max_retries=5):
    headers = {'Content-Type': 'application/json'}
    signature = generate_signature(payload, secret)
    headers['X-Signature'] = signature
    
    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=payload, headers=headers, timeout=10)
            if response.status_code < 500 and response.status_code != 429:
                return response.status_code
        except RequestException:
            pass
        
        # 지터를 사용한 지수 백오프
        delay = (2 ** attempt) + (random.random() * 0.1)
        time.sleep(delay)
    
    return None  # 재시도 후 실패

프로덕션에서는 실패한 시도를 큐에 저장하고 비동기적으로 처리합니다. Celery 또는 클라우드 큐(AWS SQS, Google Cloud Tasks)와 같은 도구가 도움이 될 수 있습니다.

웹훅 보안을 위한 모범 사례

중복 처리 및 멱등성

재시도로 인해 중복 전달이 발생할 수 있습니다. 페이로드에 고유한 이벤트 ID를 포함하고 수신자가 처리된 ID를 추적하도록 하세요. 이벤트 ID가 이전에 본 적이 있으면 무시합니다.

또는 이벤트 핸들러를 멱등적으로 설계하세요. 예를 들어 동일한 데이터로 레코드를 여러 번 업데이트하는 것은 한 번 수행하는 것과 동일한 효과를 가져야 합니다.

웹훅 테스트

ngrok과 같은 도구를 사용하여 로컬 서버를 노출하고 웹훅 전달을 테스트하세요. 오류 코드를 반환하여 실패를 시뮬레이션하고 재시도가 예상대로 발생하는지 확인하세요.

FAQ

서명된 웹훅 페이로드란 무엇인가요?

서명된 페이로드에는 수신자가 요청이 신뢰할 수 있는 소스에서 왔고 변경되지 않았음을 확인할 수 있는 암호화 서명(일반적으로 HMAC)이 포함됩니다.

실패한 웹훅을 몇 번 재시도해야 하나요?

안정성 요구 사항에 따라 다릅니다. 일반적인 방법은 24시간 동안 지수 백오프를 사용하여 5-10회 재시도하는 것입니다. 항상 구독자가 수동으로 재시도를 트리거할 수 있도록 허용하세요.

서명 없이 웹훅을 사용할 수 있나요?

가능하지만 위험합니다. 서명이 없으면 누구나 가짜 이벤트를 보낼 수 있습니다. 사기를 방지하려면 프로덕션에서 항상 웹훅에 서명하세요.

웹훅 페이로드를 테스트할 준비가 되셨나요? JSON 페이로드를 보내기 전에 유효성을 검사하고 예쁘게 출력하려면 JSON Formatter를 사용하세요.