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

Backend2026-10-26TryQuickToolBox

웹훅에 서명된 페이로드와 재시도가 필요한 이유

여러분이 방금 웹훅을 엔드포인트로 보내는 서드파티 서비스를 통합했다고 가정해 봅시다. 테스트에서는 모든 것이 잘 작동하지만, 프로덕션에서는 이벤트 누락, 중복 전달, 그리고 더 심각하게는 누군가 웹훅 URL로 요청을 스푸핑하는 문제를 발견하게 됩니다. 적절한 보안 및 안정성 조치가 없으면 웹훅은 버그와 취약점의 원인이 될 수 있습니다.

웹훅은 이벤트가 발생했을 때 애플리케이션에 알리는 HTTP 콜백입니다. 개념은 간단하지만 신뢰 경계를 넘나들고 네트워크 안정성 문제를 겪기 때문에 실제로는 까다롭습니다. 이 가이드에서는 두 가지 중요한 측면을 다룹니다: 진위 여부를 확인하는 서명된 페이로드와 전달을 보장하는 재시도입니다. 즉시 적용할 수 있는 실용적인 구현 방법을 살펴보겠습니다.

서명된 페이로드 이해하기

서명된 페이로드는 발신자가 웹훅이 자신으로부터 왔고 변조되지 않았음을 증명하는 방법입니다. 발신자는 공유 비밀을 사용하여 요청 본문(때로는 헤더)에 대한 암호화 서명을 계산한 다음 해당 서명을 헤더에 포함합니다. 엔드포인트는 서명을 다시 계산하여 비교합니다.

가장 일반적인 알고리즘은 HMAC-SHA256입니다. 빠르고 안전하며 널리 지원됩니다. 작동 방식은 다음과 같습니다:

  1. 발신자와 수신자는 비밀 키를 공유합니다(웹훅 설정에서 구성).
  2. 각 웹훅에 대해 발신자는 HMAC-SHA256을 사용하여 비밀 키로 페이로드를 해싱하여 서명을 생성합니다.
  3. 서명은 X-Signature와 같은 헤더로 전송됩니다.
  4. 수신자는 동일한 HMAC을 계산하고 타이밍 공격을 방지하기 위해 상수 시간 비교를 사용하여 비교합니다.

Node.js에서 HMAC 검증 구현하기

구체적인 예를 살펴보겠습니다. 발신자가 X-Signature에 16진수 문자열로 서명을 포함한다고 가정합니다. Express 라우트에서 검증하는 방법은 다음과 같습니다:

const crypto = require('crypto');
const express = require('express');
const app = express();

// 서명 검증을 위해 원시 본문 사용
app.use('/webhook', express.raw({ type: 'application/json' }));

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-signature'];
  const secret = process.env.WEBHOOK_SECRET;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(req.body)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature');
  }

  // 이벤트 처리
  const event = JSON.parse(req.body);
  console.log('Received event:', event.type);

  res.status(200).send('OK');
});

app.listen(3000);

중요: 서명 계산에는 항상 원시 요청 본문을 사용하고, 파싱된 JSON을 사용하지 마세요. 파싱하고 다시 문자열로 변환하면 공백과 순서가 변경되어 서명이 깨질 수 있습니다.

타임스탬프 및 재전송 공격 방지

서명만으로는 재전송 공격을 막을 수 없습니다. 공격자는 유효한 서명된 요청을 캡처하여 나중에 다시 보낼 수 있습니다. 이를 완화하려면 서명된 페이로드나 헤더에 타임스탬프를 포함하세요. 예를 들어 Unix 시간이 포함된 X-Timestamp 헤더를 추가합니다. 수신자는 타임스탬프가 허용 범위(예: 5분) 내에 있는지 확인하고 오래된 요청을 거부합니다.

또한 변조를 방지하기 위해 서명 계산에 타임스탬프를 포함하세요. 발신자는 timestamp + '.' + body에 대한 HMAC을 계산합니다. 수신자도 동일하게 수행하고 비교합니다.

안정적인 전달을 위한 재시도 구현

웹훅은 공용 인터넷을 통해 이동하므로 실패는 불가피합니다: 네트워크 시간 초과, 서버 오류(5xx), 또는 엔드포인트가 일시적으로 다운되는 경우입니다. 강력한 웹훅 시스템은 실패한 전달을 재시도해야 합니다.

재시도 전략

일반적인 재시도 전략은 다음과 같습니다:

일반적인 정책은 10초부터 시작하여 지수 백오프와 지터를 사용하여 최대 5회 재시도하는 것입니다. 그 후에는 전달을 실패로 표시하고 경고를 보낼 수 있습니다.

멱등성: 중복 처리

재시도는 중복 전달을 일으킬 수 있습니다. 엔드포인트는 멱등성을 가져야 합니다. 즉, 동일한 이벤트를 두 번 처리해도 고객에게 이중 청구하는 것과 같은 부작용이 발생하지 않아야 합니다. 페이로드에 고유한 이벤트 ID(예: event.id)를 포함하고 처리된 ID를 합리적인 기간 동안 저장하세요. 처리하기 전에 해당 ID가 이미 본 것인지 확인하세요.

또는 작업을 자연스럽게 멱등적으로 설계할 수 있습니다(예: 삽입 대신 upsert 사용).

빠른 응답

웹훅 엔드포인트는 수신을 빠르게(몇 초 이내) 확인하고 이벤트를 비동기적으로 처리해야 합니다. 처리가 너무 오래 걸리면 발신자가 시간 초과되어 재시도하여 중복이 발생할 수 있습니다. 큐를 사용하세요: 서명을 확인한 직후 200 OK로 응답한 다음 이벤트를 백그라운드 처리 대기열에 넣습니다.

웹훅 보안 조치 비교

조치 목적 구현 복잡성
HMAC 서명 진위 및 무결성 확인 낮음
타임스탬프 검증 재전송 공격 방지 낮음
멱등성 키 중복 처리 방지 중간
IP 허용 목록 알려진 발신자 IP로 제한 낮음 (하지만 취약함)
HTTPS 전송 중 데이터 암호화 낮음

IP 허용 목록은 계층을 추가할 수 있지만 발신자 IP가 변경될 수 있으므로 신뢰할 수 없습니다. 주로 서명에 의존하세요.

웹훅 엔드포인트 테스트

ngrok과 같은 도구를 사용하여 로컬 서버를 노출하고 제공업체 대시보드에서 테스트 웹훅을 트리거하세요. 서명이 올바르게 검증되는지 확인하고 실패를 시뮬레이션하여(예: 처음 몇 번의 시도에 대해 500 반환) 재시도가 작동하는지 확인하세요.

디버깅할 때 JSON 페이로드를 검사해야 할 수 있습니다. JSON Formatter를 사용하면 웹훅 페이로드를 빠르게 예쁘게 인쇄하고 유효성을 검사할 수 있습니다.

FAQ

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

서명된 페이로드에는 수신자가 요청이 예상 발신자로부터 왔고 변경되지 않았음을 확인할 수 있는 암호화 서명(일반적으로 HMAC)이 포함됩니다. 공유 비밀을 사용하여 계산됩니다.

실패한 웹훅을 몇 번 재시도해야 하나요?

보편적인 숫자는 없지만 지수 백오프를 사용한 3~5회 재시도가 일반적입니다. 그 후에는 실패를 기록하고 경고를 고려하세요. 목표는 무한 재시도 없이 일시적인 문제를 처리하는 것입니다.

웹훅 서명에 JWT를 사용할 수 있나요?

예, 일부 제공업체는 JWT(JSON Web Tokens)를 사용하여 웹훅에 서명합니다. 토큰에는 클레임이 포함되어 있으며 비밀 또는 개인 키로 서명됩니다. 검증은 유사합니다: 서명을 유효성 검사하고 만료와 같은 클레임을 확인합니다.

안전한 웹훅을 구현할 준비가 되셨나요? 강력한 비밀을 생성하고, HMAC 검증을 추가하고, 멱등성을 갖춘 재시도를 설정하는 것으로 시작하세요. 개발 중 빠른 페이로드 검사를 위해 JSON Formatter를 사용하여 웹훅 JSON을 포맷하고 유효성을 검사해 보세요.