웹훅 완벽 가이드: 서명된 페이로드와 재시도
결제 게이트웨이나 CI/CD 서비스를 연동한 후 실시간 이벤트를 받아야 하는 상황이 생깁니다. 웹훅은 표준적인 해결책이지만 함정이 있습니다. 인증되지 않은 페이로드, 손실된 이벤트, 중복 전달 등이 그것입니다. 이 글에서는 웹훅의 작동 방식, 변조를 방지하기 위한 페이로드 서명 방법, 안정적인 전달을 위한 재시도 구현 방법을 설명합니다.
웹훅이란 무엇인가?
웹훅은 사용자가 정의한 HTTP 콜백입니다. 애플리케이션이 API를 폴링하여 업데이트를 확인하는 대신, 이벤트가 발생할 때마다 제공자가 지정한 URL로 HTTP POST 요청을 보냅니다. 이는 더 효율적이며 거의 실시간으로 반응할 수 있게 해줍니다.
일반적인 사용 사례는 다음과 같습니다:
- 결제 알림 (예: Stripe, PayPal)
- CI/CD 빌드 상태 (예: GitHub, GitLab)
- 메시징 플랫폼 (예: Slack, Discord)
- CRM 업데이트 (예: Salesforce)
웹훅 페이로드에 서명해야 하는 이유
웹훅 엔드포인트는 공개적으로 접근 가능한 URL입니다. 검증 없이는 누구나 가짜 페이로드를 보낼 수 있어 데이터 손상이나 보안 침해로 이어질 수 있습니다. 공유 비밀 키로 페이로드에 서명하면 진위성과 무결성을 보장할 수 있습니다.
대부분의 제공자는 SHA-256과 함께 HMAC(Hash-based Message Authentication Code)을 사용합니다. 제공자는 비밀 키를 사용하여 원시 요청 본문에 대한 서명을 계산하고 이를 헤더(예: X-Hub-Signature-256)에 포함합니다. 서버는 서명을 다시 계산하여 비교합니다.
서명 검증 방법
단계별 가이드는 다음과 같습니다:
- 원시 본문을 가져옵니다. 전송된 그대로여야 합니다. 검증 전에 파싱하거나 수정하지 마세요.
- 헤더에서 서명을 추출합니다.
- 비밀 키를 사용하여 HMAC-SHA256으로 예상 서명을 계산합니다.
- 타이밍 공격을 방지하기 위해 상수 시간 함수로 비교합니다.
Node.js 예제:
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
const digest = 'sha256=' + hmac.update(payload).digest('hex');
return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(signature));
}
Python 예제:
import hmac
import hashlib
def verify_signature(payload, signature, secret):
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(f'sha256={expected}', signature)
정보 유출을 방지하려면 항상 상수 시간 비교를 사용하세요.
안정성을 위한 재시도 구현
네트워크는 실패하고, 서버는 재시작되며, 배포는 이루어집니다. 견고한 웹훅 시스템은 실패한 전달을 재시도해야 합니다. 제공자는 일반적으로 지수 백오프로 재시도하지만, 수신 측에서도 재시도를 처리해야 합니다.
재시도 전략
- 지수 백오프: 재시도 간격을 1초, 2초, 4초, 8초 등으로 늘립니다.
- 최대 시도 횟수: 무한 루프를 피하기 위해 재시도를 제한합니다 (예: 5회).
- 데드 레터 큐: 최대 시도 후 수동 검사를 위해 이벤트를 저장합니다.
- 멱등성: 동일한 이벤트를 여러 번 처리해도 중복 부작용이 발생하지 않도록 보장합니다.
멱등성 키
많은 제공자가 고유한 이벤트 ID(예: X-Event-ID)를 포함합니다. 처리된 ID를 데이터베이스나 캐시에 저장하여 중복을 건너뜁니다. 예를 들어 Redis와 TTL을 사용하여 확인된 ID를 추적할 수 있습니다.
비교: 폴링 vs 웹훅
| 측면 | 폴링 | 웹훅 |
|---|---|---|
| 지연 시간 | 간격에 따라 다름 | 거의 실시간 |
| 서버 부하 | 높음 (지속적인 요청) | 낮음 (이벤트 발생 시에만) |
| 복잡성 | 구현이 간단함 | 엔드포인트, 보안, 재시도 필요 |
| 안정성 | 폴링 사이의 이벤트를 놓침 | 엔드포인트 다운 시 놓칠 수 있음; 재시도가 도움됨 |
웹훅 소비자를 위한 모범 사례
- 빠르게 응답: 몇 초 이내에 2xx를 반환하고 비동기적으로 처리하세요.
- 서명 검증: 처리 전에 항상 검증하세요.
- 모든 것을 로깅: 디버깅을 위해 원시 페이로드와 헤더를 보관하세요.
- HTTPS 사용: 일반 HTTP로 웹훅을 수신하지 마세요.
- 실패 모니터링: 반복적인 재시도 실패에 대한 알림을 설정하세요.
자주 묻는 질문
웹훅 서명이란 무엇인가요?
웹훅 서명은 공유 비밀 키로 생성된 페이로드의 HMAC 해시입니다. 수신자가 요청이 예상 발신자로부터 왔고 변조되지 않았음을 확인할 수 있게 해줍니다.
실패한 웹훅을 몇 번 재시도해야 하나요?
보편적인 숫자는 없지만 지수 백오프를 사용한 3~5회 재시도가 일반적입니다. 그 후에는 수동 검토를 위해 이벤트를 데드 레터 큐에 로깅하세요.
HTTPS 없이 웹훅을 사용할 수 있나요?
기술적으로는 가능하지만 매우 안전하지 않습니다. 페이로드를 암호화하고 중간자 공격을 방지하려면 항상 HTTPS를 사용하세요.
웹훅 엔드포인트를 테스트할 준비가 되셨나요? JSON Formatter를 사용하여 페이로드를 빠르게 검사하고 검증해보세요.