웹훅 이해하기: 서명된 페이로드와 재시도 전략
웹훅을 보내는 타사 서비스를 방금 통합했고 테스트에서는 모든 것이 잘 작동합니다. 하지만 프로덕션에서는 간혹 이벤트가 누락되거나 중복 전달되거나, 더 심각하게는 악의적인 공격자가 가짜 페이로드를 엔드포인트로 보내는 것을 발견할 수 있습니다. 웹훅은 개념적으로는 간단하지만 실제로는 까다롭습니다. 이 글에서는 서명된 페이로드로 웹훅을 보호하고, 안정적인 재시도 전략을 구현하여 이벤트 기반 통합을 신뢰할 수 있도록 하는 방법을 설명합니다.
웹훅이란 무엇이며 왜 중요한가
웹훅은 특정 이벤트에 의해 트리거되는 사용자 정의 HTTP 콜백입니다. 결제 성공이나 신규 사용자 가입과 같은 이벤트가 발생하면 소스 서비스는 사용자가 제공한 URL로 HTTP POST 요청을 보냅니다. 이 푸시 기반 모델은 폴링보다 효율적이어서 지연 시간과 서버 부하를 줄입니다. 그러나 진위 확인과 전달 실패 처리라는 과제를 안고 있습니다.
서명된 페이로드로 웹훅 보호하기
검증 없이는 누구나 웹훅 엔드포인트로 요청을 보낼 수 있습니다. 서명된 페이로드는 요청이 신뢰할 수 있는 발신자로부터 왔음을 증명하는 암호화 서명을 포함하여 이 문제를 해결합니다.
HMAC 서명 작동 방식
대부분의 제공업체는 공유 비밀을 사용하는 HMAC(해시 기반 메시지 인증 코드)을 사용합니다. 발신자는 비밀을 사용하여 페이로드의 해시를 계산하고 이를 헤더(예: X-Signature)에 포함합니다. 서버는 해시를 다시 계산하여 비교합니다. 일치하면 요청이 진본입니다.
// 예: Node.js에서 웹훅 서명 검증
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(payload);
const digest = hmac.digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}
중요: 타이밍 공격을 방지하려면 항상 타이밍 안전 비교를 사용하세요. 또한 구문 분석된 JSON 객체가 아닌 원시 요청 본문에 대해 서명을 검증하세요. 구문 분석 과정에서 페이로드가 변경될 수 있기 때문입니다.
서명 검증 모범 사례
- HTTPS 사용: 도청을 방지하려면 항상 TLS를 통해 웹훅을 제공하세요.
- 비밀 교체: 서명 비밀을 주기적으로 교체하고 교체 중에는 여러 활성 비밀을 지원하세요.
- 타임스탬프 검증: 재전송 공격을 방지하기 위해 서명에 타임스탬프를 포함하세요. 몇 분 이상 지난 요청은 거부하세요.
- 실패 로깅: 서명 검증 실패를 모니터링하여 공격이나 잘못된 구성을 감지하세요.
안정적인 재시도 구현하기
서명된 페이로드가 있더라도 네트워크 문제나 일시적인 중단으로 인해 웹훅 전달이 실패할 수 있습니다. 강력한 재시도 전략은 시스템에 과부하를 주지 않으면서 이벤트가 결국 전달되도록 보장합니다.
지터를 포함한 지수 백오프
즉시 재시도하면 혼잡이 악화될 수 있습니다. 대신 지수 백오프를 사용하세요: 각 재시도 사이에 더 오래 기다립니다. 많은 웹훅이 동시에 실패할 때 몰려드는 문제를 피하기 위해 지터(무작위 변동)를 추가하세요.
// 예: 지수 백오프와 지터를 사용한 재시도 일정
function getRetryDelay(attempt) {
const base = 1000; // 1초
const max = 30000; // 30초
const delay = Math.min(base * Math.pow(2, attempt), max);
return delay + Math.random() * 1000; // 최대 1초 지터 추가
}
멱등성: 중복 처리
재시도로 인해 중복 전달이 발생할 수 있습니다. 웹훅 핸들러는 멱등성이 있어야 합니다. 즉, 동일한 이벤트를 여러 번 처리해도 한 번 처리한 것과 같은 효과를 내야 합니다. 페이로드의 이벤트 ID를 사용하여 처리된 이벤트를 추적하세요.
- 처리된 이벤트 ID를 TTL과 함께 데이터베이스에 저장하세요.
- 처리하기 전에 이벤트 ID가 이미 존재하는지 확인하고, 존재하면 즉시 성공 응답을 반환하세요.
- 작업을 멱등적으로 설계하세요(예: 삽입 대신 upsert 사용).
빠르게 응답하고 확인하기
웹훅 엔드포인트는 가능한 한 빠르게, 이상적으로는 몇 초 이내에 2xx 상태 코드로 응답해야 합니다. 처리가 더 오래 걸리면 이벤트를 비동기 처리 대기열에 넣고 202 Accepted를 반환하세요. 이렇게 하면 시간 초과와 불필요한 재시도를 방지할 수 있습니다.
비교: 웹훅 vs. 폴링
| 측면 | 웹훅 | 폴링 |
|---|---|---|
| 지연 시간 | 거의 실시간 | 간격에 따라 다름 |
| 서버 부하 | 낮음 (푸시만) | 높음 (지속적인 요청) |
| 복잡성 | 높음 (재시도, 보안 필요) | 낮음 |
| 안정성 | 재시도 로직 필요 | 본질적으로 안정적 |
단계별: 안전한 웹훅 수신기 구축
- 유효한 인증서가 있는 HTTPS 엔드포인트를 설정하세요.
- 서명 헤더(예:
X-Signature)와 타임스탬프를 추출하세요. - 공유 비밀과 원시 본문을 사용하여 서명을 검증하세요.
- 타임스탬프를 확인하여 오래된 요청(예: 5분 이상)을 거부하세요.
- 페이로드를 구문 분석하고 중복 이벤트 ID가 있는지 확인하세요.
- 필요한 경우 이벤트를 비동기적으로 처리하고 200 OK로 응답하세요.
- 감사 및 디버깅을 위해 이벤트를 로깅하세요.
자주 묻는 질문
서명된 웹훅 페이로드란 무엇인가요?
서명된 페이로드는 수신자가 요청이 신뢰할 수 있는 소스에서 왔고 변조되지 않았음을 확인할 수 있게 해주는 암호화 서명(보통 HMAC)을 포함합니다.
실패한 웹훅을 몇 번 재시도해야 하나요?
대부분의 시스템은 지수 백오프를 사용하여 3~5회 재시도합니다. 그 후에는 일반적으로 이벤트가 실패로 표시되며 수동 개입이나 데드 레터 큐 처리가 필요할 수 있습니다.
HTTPS 없이 웹훅을 사용할 수 있나요?
강력히 권장하지 않습니다. HTTPS가 없으면 페이로드와 서명이 가로채이거나 수정될 수 있습니다. 항상 웹훅 엔드포인트에 TLS를 사용하세요.
웹훅 페이로드나 로그를 디버깅할 때 JSON 형식을 올바르게 지정하는 것이 필수적입니다. JSON Formatter를 사용하여 JSON 페이로드를 빠르게 예쁘게 출력하고 유효성을 검사하세요.