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

Backend2026-10-25TryQuickToolBox

API를 구축했고 이제 이벤트가 발생할 때 다른 서비스에 알림을 보내야 합니다. 웹훅을 구현하기로 결정했습니다: 구독자 URL로 데이터를 푸시하는 HTTP 콜백입니다. 하지만 곧 두 가지 중요한 질문에 직면합니다: 페이로드가 변조되지 않았음을 어떻게 보장할까? 그리고 수신 서버가 다운되거나 오류를 반환하면 어떻게 될까? 적절한 보호 장치가 없으면 웹훅은 보안 허점이자 안정성 악몽이 될 수 있습니다.

이 가이드에서는 서명된 페이로드로 웹훅을 보호하고 강력한 재시도 로직을 구현하는 핵심 사항을 살펴봅니다. HMAC 서명을 생성하고 검증하는 방법, 멱등성 핸들러를 설계하는 방법, 실패를 원활하게 처리하는 재시도 메커니즘을 구축하는 방법을 배우게 됩니다. 마지막에는 프로덕션 환경에 바로 적용할 수 있는 웹훅 접근 방식을 갖추게 될 것입니다.

웹훅에 보안과 안정성이 필요한 이유

웹훅은 기본적으로 이벤트에 의해 트리거되는 서버 간 HTTP 요청입니다. 클라이언트가 시작하는 API 호출과 달리 웹훅은 서버에서 구독자의 엔드포인트로 푸시됩니다. 이 푸시 모델은 두 가지 주요 과제를 야기합니다:

이러한 과제를 무시하면 데이터 유출, 이벤트 손실 또는 시스템 간 상태 불일치가 발생할 수 있습니다. 하나씩 해결해 보겠습니다.

서명된 페이로드로 웹훅 보호하기

서명된 페이로드는 암호화 해시를 사용하여 요청의 무결성과 신뢰성을 증명합니다. 가장 일반적인 접근 방식은 공유 비밀을 사용한 HMAC(해시 기반 메시지 인증 코드)입니다. 작동 방식은 다음과 같습니다:

  1. 공유 비밀: 발신자(귀하의 서비스)와 수신자(구독자)가 비밀 키를 공유합니다. 이 키는 구독자가 웹훅 엔드포인트를 등록할 때 생성됩니다.
  2. 서명 생성: 각 웹훅 요청에 대해 발신자는 비밀을 사용하여 요청 본문(때로는 타임스탬프와 같은 헤더)의 HMAC을 계산합니다. 서명은 X-Signature와 같은 헤더로 전송됩니다.
  3. 서명 검증: 수신자는 동일한 비밀을 사용하여 HMAC을 다시 계산하고 수신된 서명과 비교합니다. 일치하면 페이로드가 진본이며 수정되지 않았음을 의미합니다.

Node.js에서 서명을 생성하고 검증하는 코드 예제를 살펴보겠습니다.

const crypto = require('crypto');

// 발신자: 서명 생성
function generateSignature(payload, secret) {
  return crypto.createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
}

// 수신자: 서명 검증
function verifySignature(payload, secret, receivedSignature) {
  const expectedSignature = generateSignature(payload, secret);
  // 타이밍 공격을 방지하기 위해 timingSafeEqual 사용
  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature, 'hex'),
    Buffer.from(receivedSignature, 'hex')
  );
}

중요: 타이밍 공격을 피하려면 항상 timingSafeEqual과 같은 상수 시간 비교 함수를 사용하세요. 또한 재전송 공격을 방지하기 위해 서명된 데이터에 타임스탬프를 포함하세요. 예를 들어 timestamp + '.' + payload에 서명하고 몇 분 이상 지난 요청은 거부합니다.

서명된 페이로드 모범 사례

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

보안이 갖춰져 있어도 네트워크 문제, 서버 오류 또는 시간 초과로 인해 웹훅이 실패할 수 있습니다. 강력한 재시도 메커니즘은 이벤트가 결국 전달되도록 보장합니다. 단계별 접근 방식은 다음과 같습니다:

  1. 시간 초과 설정: 웹훅 요청에 합리적인 시간 초과(예: 10초)를 정의합니다. 구독자가 제시간에 응답하지 않으면 실패로 간주합니다.
  2. 응답 분류: 2xx 상태 코드는 성공으로 처리합니다. 4xx 오류(429 제외)의 경우 요청이 유효하지 않으므로 재시도는 일반적으로 무의미합니다. 5xx 오류 및 시간 초과의 경우 지수 백오프로 재시도합니다.
  3. 지터를 포함한 지수 백오프: 증가하는 간격(예: 1초, 5초, 30초, 5분, 30분)으로 재시도를 예약하고 무리 효과를 피하기 위해 무작위 지터를 추가합니다.
  4. 재시도 제한: 최대 시도 횟수(예: 5회)를 설정한 후 전달 실패로 표시합니다. 선택적으로 이메일이나 대시보드를 통해 구독자에게 알립니다.
  5. 멱등성: 재시도로 인해 중복 전달이 발생할 수 있으므로 페이로드와 헤더에 고유한 이벤트 ID를 포함합니다. 구독자는 이 ID를 사용하여 처리를 중복 제거해야 합니다.

다음은 requests와 time을 사용한 Python의 간단한 재시도 큐 구현입니다:

import requests
import time
import random

def deliver_webhook(url, payload, secret, max_retries=5):
    signature = generate_signature(payload, secret)
    headers = {'X-Signature': signature, 'Content-Type': 'application/json'}
    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=payload, headers=headers, timeout=10)
            if 200 <= response.status_code < 300:
                return True
            elif response.status_code == 429 or 500 <= response.status_code < 600:
                # 재시도 가능한 오류
                pass
            else:
                # 재시도 불가능한 오류
                return False
        except requests.exceptions.RequestException:
            # 네트워크 오류, 재시도
            pass
        # 지터를 포함한 지수 백오프
        delay = min(30, 2 ** attempt) + random.uniform(0, 1)
        time.sleep(delay)
    return False

멱등성: 중복 전달 처리

재시도로 인해 동일한 이벤트가 여러 번 전달될 수 있으므로 구독자는 멱등 처리 를 구현해야 합니다. 표준 접근 방식은 페이로드에 고유한 이벤트 ID(예: UUID)를 포함하고 수신자가 처리된 ID를 일정 기간 동안 저장하는 것입니다. 중복 ID가 수신되면 수신자는 재처리 없이 확인 응답합니다.

다음은 웹훅 핸들러의 간단한 멱등성 검사입니다:

processed_events = set()

def handle_webhook(event):
    event_id = event['id']
    if event_id in processed_events:
        return 'already processed'
    # 이벤트 처리
    processed_events.add(event_id)
    return 'success'

프로덕션에서는 Redis나 TTL이 있는 데이터베이스와 같은 영구 저장소를 사용하여 처리된 ID를 추적하세요.

비교: 서명된 페이로드 vs. 기타 보안 조치

접근 방식 장점 단점
HMAC 서명된 페이로드 강력한 무결성 및 신뢰성, 비밀 전송 없음 공유 비밀 관리 필요
기본 인증 구현 간단 모든 요청에 자격 증명 전송, 보안 취약
IP 허용 목록 승인되지 않은 소스 차단 IP 변경 가능, 동적 환경에 부적합
OAuth2 클라이언트 자격 증명 표준화, 토큰 기반 간단한 웹훅에는 과도함, 토큰 관리 오버헤드

HMAC 서명된 페이로드는 대부분의 웹훅 사용 사례에서 보안과 단순성 사이의 좋은 균형을 제공합니다.

모두 통합하기

안정적이고 안전한 웹훅 시스템을 구축하려면:

웹훅 전달을 디버깅할 때 원시 HTTP 요청과 응답을 검사하는 것은 매우 유용합니다. Nginx 로그로 수신 웹훅 요청을 추적하는 경우, Nginx 로그 분석기를 사용하여 로그 항목을 구문 분석하고 필터링하여 실패한 전달이나 의심스러운 패턴을 식별할 수 있습니다.

FAQ

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

서명된 웹훅 페이로드에는 수신자가 요청의 신뢰성과 무결성을 검증할 수 있도록 암호화 서명(일반적으로 HMAC)이 포함됩니다. 발신자는 공유 비밀을 사용하여 서명을 계산하고 헤더에 포함합니다. 수신자는 이를 다시 계산하고 비교합니다.

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

일반적인 방법은 지수 백오프를 사용하여 3~5회 재시도하는 것입니다. 그 후에는 전달 실패로 표시하고 구독자에게 알립니다. 정확한 횟수는 SLA와 이벤트의 중요도에 따라 다릅니다.

웹훅에서 멱등성이 중요한 이유는 무엇인가요?

재시도로 인해 중복 전달이 발생할 수 있습니다. 멱등성은 동일한 이벤트를 여러 번 처리해도 한 번 처리한 것과 동일한 효과를 보장하여 데이터 손상이나 중복 작업을 방지합니다.