웹훅 서명 검증
검증 절차
- 원본 페이로드 확보 – 웹훅 라우터에서 JSON 자동 파싱을 비활성화하고 서명에 사용된 바이트 스트림 그대로를 확보합니다.
- 헤더 읽기 –
X-Webhook-Signature(소문자 16진수 다이제스트, 시크릿 미설정 시 헤더 없음)와X-Webhook-Timestamp(밀리초 단위 문자열)을 추출합니다. 문자열을 그대로 보존하세요. - 예상 서명 계산 –
HMAC_SHA256(secret, rawBody)를 계산한 뒤 소문자 16진수로 변환해 헤더 값과 직접 비교합니다. 플랫폼은 접두사를 붙이지 않습니다. - 상수시간 비교 – 계산 값과 헤더 값을 상수시간 비교 함수로 비교해 다르면 거부합니다.
==등은 사용하지 마세요. - 타임스탬프 검증 – 5분 이내인지 확인해 재전송 공격을 차단합니다. JSON 본문에도
timestamp(초 단위)가 있으므로 함께 검증합니다. - 이벤트 처리 – 검증이 끝나면 즉시
200을 응답하고 비동기로 처리합니다. MIRI는 초 간격으로 최대 3회 재시도하므로 멱등 로직을 구현해야 합니다.
이벤트 구조
{
"event": "analysis.completed",
"timestamp": 1704445800, // 본문은 epoch 초 단위. 헤더 X-Webhook-Timestamp는 epoch 밀리초 사용
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "analysis",
"status": "COMPLETED"
}
}
모든 이벤트는 이 구조를 따릅니다. 본문 timestamp는 초 단위이며 헤더 X-Webhook-Timestamp는 밀리초 단위이므로 두 값을 함께 검증하세요.
이벤트 페이로드
| 이벤트 | data 필드 | 비고 |
|---|---|---|
analysis.completed | id(분석 UUID), type = "analysis", status = "COMPLETED" | 상세 결과는 분석 API로 조회하세요. |
analysis.failed | analysisId(분석 UUID)와 error 메시지. 일부 실패 흐름에서는 type, status, id도 함께 전달됩니다. | 처리 중 오류 또는 타임아웃 시 발생 |
batch.completed | id, type = "batch", status = "COMPLETED", totalCount, completedCount, failedCount, completedAt | 모든 항목 성공 |
batch.partial | batch.completed와 동일한 필드, status = "FAILED" | 일부 항목만 실패 |
batch.failed | batch.completed와 동일한 필드, status = "FAILED" | 모든 항목 실패 |
batch.cancelled | batch.completed와 동일한 필드, status = "CANCELLED" | 사용자 취소 |
헤더
| 헤더 | 설명 |
|---|---|
X-Webhook-Event | 이벤트 타입 (예: analysis.completed) |
X-Webhook-Timestamp | 재전송 방지용 Epoch 밀리초 |
X-Webhook-Signature | HMAC_SHA256(secret, body)의 소문자 16진수 다이제스트 (시크릿이 없으면 헤더 없음) |
이벤트
analysis.completed- 분석 실행 완료analysis.failed- 분석 실패 (페이로드에 오류 메시지 포함)batch.completed- 모든 항목 성공batch.partial- 일부 항목 실패batch.failed- 전체 실패batch.cancelled- 배치 취소
재시도 정책
각 이벤트는 2초 간격으로 최대 3회까지 시도합니다(application.yml 구성). 모든 시도가 실패하면 해당 전송은 실패로 기록되며, URL 또는 시크릿을 수정한 뒤 분석이나 배치를 다시 실행하면 새 알림이 발송됩니다.
프로덕션 요구사항
- HTTPS 권장 - 플랫폼이 HTTP를 차단하지는 않지만, TLS로 페이로드·시크릿을 보호하세요.
- 응답 시간 - 10초 이내 응답 필수
- 멱등성 -
analysisId + event를 키로 중복 이벤트 처리 - 비동기 처리 - 즉시 200 응답 후 비동기 처리
- 시크릿 관리 - 영문/숫자 혼합 32자 이상(64자 권장) 시크릿을 사용하고 주기적으로 교체하세요.