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

Backend2026-11-03TryQuickToolBox

방금 타사 결제 제공업체를 통합했습니다. 사용자가 구매를 완료했지만 데이터베이스는 업데이트되지 않았습니다. 왜일까요? 앱에 알림을 보내야 했던 웹훅이 조용히 실패했기 때문입니다. 적절한 서명 검증과 재시도 로직이 없으면 웹훅은 알 수 없는 버그와 보안 취약점의 원천이 될 수 있습니다.

이 글에서는 웹훅이 어떻게 작동하는지, 왜 서명된 페이로드를 반드시 검증해야 하는지, 그리고 견고한 재시도 메커니즘을 설계하는 방법을 설명합니다. 또한 웹훅을 효과적으로 테스트하고 디버깅하는 방법도 보여드립니다.

웹훅이란 무엇인가?

웹훅은 사용자가 정의한 HTTP 콜백입니다. 이벤트가 발생할 때 한 시스템이 다른 시스템으로 실시간 데이터를 전송할 수 있게 해줍니다. 예를 들어 결제가 처리되면 결제 제공업체는 이벤트 세부 정보를 담아 지정한 URL로 HTTP POST 요청을 보냅니다.

앱이 반복적으로 업데이트를 요청하는 폴링과 달리, 웹훅은 데이터가 준비되는 즉시 데이터를 푸시합니다. 따라서 효율적이고 거의 실시간에 가깝습니다.

보안 문제: 왜 서명을 검증해야 하는가?

웹훅 엔드포인트는 공개적으로 접근 가능한 URL입니다. 누구나 POST 요청을 보낼 수 있습니다. 검증이 없으면 공격자가 요청을 위조하여 실제 결제 없이 주문을 결제 완료로 표시할 수 있습니다. 이를 방지하기 위해 제공업체는 비밀 키로 각 페이로드에 서명합니다.

HMAC 서명의 작동 방식

대부분의 제공업체는 SHA-256과 함께 HMAC(Hash-based Message Authentication Code)을 사용합니다. 공유 비밀을 사용해 요청 본문의 해시를 계산하고 X-Signature와 같은 헤더에 포함합니다. 서버는 해시를 다시 계산하여 헤더와 비교합니다. 일치하면 요청이 진본입니다.

다음은 Python의 간단한 예제입니다:

import hmac
import hashlib

def verify_signature(payload, secret, signature):
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

타이밍 공격을 피하려면 항상 hmac.compare_digest와 같은 상수 시간 비교 함수를 사용하세요.

피해야 할 흔한 실수

안정적인 재시도 설계

웹훅은 인터넷을 통해 전송되므로 실패는 불가피합니다. 네트워크가 끊기고, 서버가 재시작되며, 엔드포인트가 타임아웃됩니다. 좋은 웹훅 시스템은 지수 백오프를 사용해 실패한 전달을 재시도합니다.

재시도의 일반적인 작동 방식

제공업체는 보통 점점 늘어나는 지연으로 재시도합니다: 1분, 5분, 30분 후 등, 최대 시도 횟수(예: 5-10회)까지. 모든 재시도가 실패하면 이벤트는 실패로 표시되며 수동 재전송이 가능할 수 있습니다.

엔드포인트는 수신을 확인하기 위해 2xx 상태 코드로 빠르게 응답해야 합니다. 2xx가 아닌 코드를 반환하거나 타임아웃되면 제공업체가 재시도합니다.

멱등성 구현

재시도로 인해 중복 전달이 발생할 수 있으므로 엔드포인트는 멱등해야 합니다. 페이로드나 헤더에 포함된 이벤트 ID를 사용해 처리된 이벤트를 추적하세요. 처리하기 전에 해당 ID를 이미 처리했는지 확인하세요. 처리된 ID는 TTL과 함께 데이터베이스에 저장하세요.

멱등성 검사 예제:

def process_event(event_id, data):
    if db.exists(f"processed:{event_id}"):
        return  # already processed
    # process data
    db.setex(f"processed:{event_id}", 86400, "1")  # expire after 24h

웹훅 수신기 구축: 단계별 안내

  1. HTTPS 엔드포인트 노출: 전송 중 데이터를 보호하기 위해 TLS를 사용하세요.
  2. 서명 검증: 유효하지 않은 서명의 요청은 401로 거부하세요.
  3. 타임스탬프 확인: 제공된 경우 허용 가능한 범위(예: 5분) 내인지 확인하세요.
  4. 페이로드 파싱: JSON 구조와 필수 필드를 검증하세요.
  5. 멱등성 확인: 이벤트 ID를 사용해 중복을 방지하세요.
  6. 비동기 처리: 즉시 200으로 응답한 후 백그라운드 작업에서 처리하여 타임아웃을 피하세요.
  7. 로깅 및 모니터링: 실패를 기록하고 알림을 설정하세요.

로컬에서 웹훅 테스트하기

개발 중에는 로컬 머신에서 웹훅을 받을 방법이 필요합니다. ngrok이나 localtunnel 같은 도구는 localhost로 전달되는 공개 URL을 생성합니다. 또는 많은 제공업체가 테스트 이벤트를 트리거하는 CLI를 제공합니다.

항상 유효한 서명과 유효하지 않은 서명 모두로 서명 검증을 테스트하세요. 오류 코드를 반환하고 제공업체의 재시도 동작을 관찰하여 재시도를 시뮬레이션하세요.

비교: 웹훅 vs. 폴링

측면웹훅폴링
실시간성거의 실시간간격에 따라 지연됨
효율성이벤트 발생 시에만 데이터 전송데이터가 없어도 빈번한 요청
복잡성엔드포인트, 서명 검증, 재시도 필요구현이 더 단순함
안정성재시도 메커니즘에 의존일정을 직접 제어

FAQ

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

서명된 페이로드는 수신자가 요청이 예상 발신자로부터 왔고 변조되지 않았음을 검증할 수 있게 해주는 암호화 서명(보통 HMAC)을 포함합니다.

웹훅은 몇 번 재시도해야 하나?

대부분의 제공업체는 지수 백오프로 5-10회 재시도합니다. 정확한 횟수는 제공업체 정책에 따라 다릅니다. 엔드포인트는 중복을 처리할 수 있도록 멱등해야 합니다.

웹훅은 어떤 HTTP 상태 코드를 반환해야 하나?

수신 성공을 확인하려면 2xx 상태 코드(예: 200 OK)를 반환하세요. 다른 코드(4xx 또는 5xx)는 실패를 알리고 재시도를 트리거합니다.

웹훅 페이로드를 테스트할 준비가 되셨나요? JSON Formatter를 사용해 JSON 페이로드를 빠르게 검증하고 보기 좋게 정리하세요.