Webhook 서명 검증 시계 오차 장애 복구 플레이북: 재시도 폭주를 멈추는 운영 기준
💡 Key Takeaways
- 웹훅 서명 실패는 코드 결함보다 시계 오차, 프록시 헤더 손실, 과도한 재시도 정책이 결합돼 커지는 경우가 많습니다.
- 장애 중에는 허용 오차를 무작정 키우기보다 검증 기준 시각과 재처리 큐 정책을 먼저 고정해야 복구 속도가 빨라집니다.
- 복구 이후에는 서명 검증 로그 필드 표준화와 재전송 상한선 합의가 재발 방지의 핵심입니다.
Webhook 서명 검증 시계 오차 장애 복구 플레이북
웹훅 서명 검증 장애는 처음에는 단순 401 증가처럼 보이지만, 실제로는 결제 상태 불일치나 중복 처리로 바로 이어질 수 있는 고위험 사건입니다. 지난 분기 우리 팀은 PG 웹훅이 갑자기 15분 동안 연속 실패하면서 환불 요청 상태가 멈춘 적이 있었고, 당시 가장 큰 문제는 실패 자체보다 재시도 폭주였습니다. 공급자 쪽은 30초 간격으로 최대 20회 재전송하고, 우리 쪽은 실패 건을 내부 큐로 다시 밀어 넣고 있어서 같은 이벤트가 짧은 시간에 수십 번 회전했습니다. 이 상황에서 팀이 처음에 놓친 포인트는 “서명 원문 생성 시각”과 “검증 서버 기준 시각”이 서로 다르다는 점이었습니다. 로그를 맞춰 보니 신규 노드 두 대의 시스템 시간이 평균 4초 빠른 상태였고, 허용 오차를 3초로 두었던 정책과 충돌했습니다. 현장에서 가장 먼저 해야 할 일은 코드 수정이 아니라 시간축을 통일해 원인을 분리하는 것입니다. 요청 본문 해시, timestamp 헤더, 서버 수신 시각을 한 화면에서 비교하면, 애플리케이션 버그인지 시계/네트워크 문제인지 10분 안에 가닥이 잡힙니다.
원인 분류는 네 가지 축으로 고정해 두면 대응이 빨라집니다. 첫째는 서명 입력 불일치입니다. 프록시나 로드밸런서가 공백·개행을 정규화하거나 문자 인코딩을 바꾸면 같은 payload라도 서명 결과가 달라집니다. 둘째는 시간 검증 정책 불일치입니다. 공급자는 timestamp를 UTC 초 단위로 보내는데, 검증 서비스가 로컬 타임존 파싱을 섞어 쓰면 특정 시간대에만 실패율이 튀는 현상이 생깁니다. 셋째는 재시도 설계 문제입니다. 공급자 재전송과 내부 재처리가 겹치면 큐가 빠르게 포화되고, 정상 이벤트까지 지연되어 장애 체감이 커집니다. 넷째는 운영 관측 부재입니다. 실패 로그에 signatureBase, skewMs, providerEventId 같은 핵심 필드가 없으면 원인 추정에 시간을 버립니다. 우리 팀은 한 번의 사고 뒤에 로그 스키마를 강제했고, 이후 동일 증상에서 원인 식별 시간이 40분에서 8분으로 줄었습니다. 장애 대응에서 중요한 건 “무엇을 의심할지”보다 “어떤 순서로 배제할지”를 미리 합의해 두는 일입니다.
실행 절차는 0~15분, 15~30분, 30~60분으로 끊어 운영합니다. 0~15분에는 실패 샘플 30건을 뽑아 공급자 이벤트 ID 기준으로 중복 비율과 시간 편차를 계산합니다. 이때 skewMs 분포가 한쪽으로 치우치면 NTP나 노드 시각 문제를 먼저 잡습니다. 15~30분에는 완화 조치를 넣습니다. 검증 허용 오차를 일시적으로 3초에서 8초로 완화하되, 동시에 이벤트 멱등 키 검사를 강화해 중복 반영을 막습니다. 그리고 실패 이벤트를 즉시 재처리 큐로 넣지 말고 지수 백오프 구간으로 분리해 폭주를 누릅니다. 30~60분에는 근본 조치를 배포합니다. 검증 함수가 쓰는 기준 시각을 단일 모듈로 통일하고, 서명 원문 생성 로직을 미들웨어 이전 단계로 이동해 프록시 변형 영향을 줄입니다. 예전에 우리는 허용 오차만 늘리고 끝냈다가, 일주일 뒤 CDN 경유 경로에서 같은 문제가 재발했습니다. 완화와 근본 조치를 분리해 같은 창에서 처리해야 야간 온콜 부담이 누적되지 않습니다.
복구 후 운영 체크리스트는 짧지만 숫자로 남겨야 의미가 있습니다. 첫째, 서명 실패율이 사고 전후로 어떻게 바뀌었는지(예: 12.4% -> 0.6%). 둘째, 이벤트 처리 지연 p95가 정상 범위로 돌아왔는지. 셋째, 동일 providerEventId의 중복 처리 건수가 줄었는지. 넷째, 시계 동기화 알림이 노드 단위로 살아 있는지. 마지막으로 주의할 점은 보안과 가용성의 균형입니다. 허용 오차를 과도하게 늘리면 재전송 공격이나 재사용 공격 표면이 넓어질 수 있어, 완화 종료 시점을 반드시 명시해야 합니다. 우리 팀은 장애 복구 직후 24시간 안에 허용 오차를 원복하고, 대신 타임스탬프 드리프트 경보 임계치를 촘촘히 조정했습니다. 또한 재시도 정책 문서를 공급자별로 분리하지 않고 공통 템플릿으로 통합해 신규 온콜도 1페이지에서 판단할 수 있게 만들었습니다. 웹훅 서명 장애는 자주 일어나지 않지만 한 번 터지면 결제 신뢰를 직접 흔드니, “검증 로직”보다 “운영 절차”를 먼저 설계해 두는 편이 결국 비용을 줄입니다.