웹훅 보안 모범 사례: 수신기 체크리스트

HTTPS로만 받고, 원본 본문의 HMAC을 상수 시간으로 검증하고, 오래된 타임스탬프는 거부하고, 이벤트 ID로 중복을 제거하고, 2xx로 빠르게 응답하세요.

읽는 시간 5분Sume
전체 글

모든 웹훅은 검증하기 전까지 신뢰하지 마세요. HTTPS 엔드포인트에서만 받고, 원본 본문에 대한 HMAC 서명을 상수 시간으로 확인하고, 재전송 공격을 막으려면 짧은 허용 시간을 벗어난 타임스탬프를 거부하세요. 이벤트 ID로 중복을 제거하고, 2xx로 빠르게 응답한 뒤 작업은 그다음에 하고, 중요한 내용은 API에서 다시 읽으세요.

Sume의 전달에는 각 검사에 필요한 것이 담겨 있습니다. 서명된 타임스탬프, 바뀌지 않는 이벤트 ID, 그리고 시크릿 교체 중에는 살아 있는 시크릿마다 서명 하나씩입니다. Sume 관련 내용은 Run 웹훅 (영문), 웹훅 (영문), 실행과 결과 (영문), 웹훅 검증 문서에서 가져왔으며, 2026-09-28에 확인했습니다.

웹훅 수신기는 무엇을 확인해야 하나요?

검사는 여섯 가지이며, 각각 다른 공격이나 장애에 대응합니다. 오른쪽 열은 Sume가 각 검사를 위해 제공하는 것입니다.

Run 웹훅 (영문), 웹훅 (영문), 실행과 결과 (영문) 기준, 2026-09-28 확인.
검사막는 것Sume에서
HTTPS 전용 엔드포인트전송 중인 전달을 읽거나 바꾸는 것localhost, 사설 대역, URL에 담긴 자격 증명, 일반 HTTP는 생성 시 거부되고 전달 시 다시 검사됨
원본 본문에 대한 서명위조되거나 변조된 전달<timestamp>.<raw_body>에 대한 HMAC-SHA256, sume-v1=<hex_signature> 형태로 전송
타임스탬프 허용 시간오래된 진짜 전달의 재전송x-sume-webhook-timestamp, 오 분이 무난한 기본값
중복 제거한 이벤트를 두 번 처리하는 것실행 웹훅은 request_id, Job 웹훅은 job_id
빠른 2xx재시도를 부르는 타임아웃시도당 10초, 최대 10회 시도
API로 확인페이로드만 믿고 조치하는 것실행 웹훅의 payload는 다시 읽을 수 있는 실행과 바이트 단위로 동일

웹훅 서명은 어떻게 올바르게 검증하나요?

검사가 제 역할을 하려면 네 가지 규칙을 지켜야 합니다. 현재 코드에서 Sume TypeScript SDK의 verifyWebhook이 뒤의 세 가지를 처리하고, 첫 번째는 직접 챙겨야 합니다. SDK 핸들러는 Sume 영상 실행용 서명된 웹훅에 있고, Python과 Go 글은 같은 검사를 직접 구현합니다.

  • JSON을 파싱하기 전에 원본 바이트를 검증하세요. 키 순서와 공백도 서명 대상의 일부이므로, 파싱했다가 다시 직렬화한 객체는 검증되지 않습니다.
  • 서명 헤더는 파싱해서 쓰고, 통째로 비교하지 마세요. 시크릿 교체 중에는 Sume가 살아 있는 시크릿마다 sume-v1= 항목을 하나씩, 최신 것부터 쉼표로 구분해 보내며, 어느 항목이든 일치하면 유효한 전달입니다. sume-v1= 접두사가 없는 항목은 건너뛰세요.
  • 상수 시간으로 비교하고, 일치하는 항목을 찾은 뒤에도 모든 항목을 비교하세요. 그래야 타이밍으로 어느 시크릿이 일치했는지 드러나지 않습니다.
  • 빈 시크릿은 거부하세요. 빈 키는 누구나 쓸 수 있는 키이므로, 설정되지 않은 환경 변수는 검사에서 실패해야 합니다. 현재 코드에서 SDK는 시크릿이 비어 있으면 false를 반환합니다.

웹훅 재전송 공격은 어떻게 막나요?

재전송 공격(replay attack)은 누군가 가로챈 진짜 요청, 즉 서명이 유효한 요청을 다시 보내는 공격입니다. 바이트가 진짜이므로 서명으로는 잡아낼 수 없습니다. 이를 잡는 검사가 두 가지 있고, 주의할 점이 하나 있습니다.

  • 오래된 타임스탬프를 거부하세요. Sume는 <timestamp>.<raw_body>에 서명하므로, 서명을 깨뜨리지 않고는 타임스탬프를 바꿀 수 없습니다. x-sume-webhook-timestamp가 허용 시간을 벗어난 전달은 거부하세요. SDK의 toleranceSeconds 기본값은 300입니다.
  • 이벤트 ID로 중복을 제거하세요. 허용 시간 안에 재전송된 요청에는 원래 요청과 같은 request_id(실행)나 job_id(Job)가 담기며, Sume가 직접 하는 재시도도 마찬가지입니다. 처리한 ID를 기록해 두고 반복되는 것은 무시하세요.
  • 정상적인 반복도 예상하세요. Sume의 다시 보내기(Redeliver)는 실제 이벤트를 새 타임스탬프와 서명으로 다시 보내므로 허용 시간 검사를 통과합니다. 반복임을 알려 주는 것은 ID입니다.

웹훅은 안전한가요?

수신기가 안전하게 만드는 만큼 안전합니다. 웹훅 URL은 공개되어 있어 누구나 요청을 보낼 수 있으며, 전달이 시크릿을 가진 쪽에서 왔음을 증명하는 것은 서명입니다. 그래서 지켜야 할 것은 시크릿입니다.

Sume는 서명 시크릿을 워크스페이스별로 파생하므로, 다른 사람의 시크릿으로는 여러분에게 서명된 전달을 검증할 수 없습니다. 이 시크릿은 API 키는 어디에 저장해야 하나요?에서처럼 API 키와 같은 방식으로 저장하고, 유출되었을 수 있다면 교체하세요. 교체 기간은 Sume 영상 실행용 서명된 웹훅에서 다룹니다. 서명이 검증되지 않으면 시크릿을 어딘가에 붙여 넣지 말고, x-sume-webhook-secret-fingerprint 헤더를 대시보드의 지문과 비교하세요.

검증한 뒤 엔드포인트는 무엇을 해야 하나요?

  • 이벤트를 내구성 있게 기록하고 2xx로 응답한 다음 처리하세요. 느린 엔드포인트는 시도당 10초 예산을 소진하고 재시도를 받습니다.
  • 모르는 이벤트 타입에는 204로 응답하세요. Sume 문서에 따르면 이렇게 해야 새로 추가된 이벤트 타입이 500과 재시도 폭주로 번지지 않습니다.
  • 최종 URL을 등록하세요. 리다이렉트는 따라가지 않으며 3xx는 실패한 시도로 칩니다. Sume의 다른 URL 규칙은 웹훅 URL이 유효하지 않다고 거부되나요?에 정리되어 있습니다.
  • 비용이 드는 조치를 하기 전에 확인하세요. Format 실행의 경우 실행 웹훅의 payload는 GET /v1/format-runs/{run_id}의 data와 바이트 단위로 동일하므로, 먼저 API에서 실행을 다시 읽을 수 있습니다. 실패하는 전달은 Sume 웹훅이 도착하지 않나요? 전달·서명 디버깅 방법에서 다룹니다.

출처

관련 글

개발자 카테고리의 다른 글

개발자 글 전체 보기

작성자 Sume