Files
llm-wiki/raw/official-docs/stripe-webhook-signature.md

11 KiB

title, source_type, url, archive_url, status, confidence, tags, related_projects, related_branches, created, last_reviewed
title source_type url archive_url status confidence tags related_projects related_branches created last_reviewed
Stripe — Webhook Signatures (official-vendor-doc) official-doc https://stripe.com/docs/webhooks/signatures https://web.archive.org/web/20260629/https://stripe.com/docs/webhooks/signatures raw high
stripe
webhook
signature
hmac
security
replay-protection
timing-attack
key-rotation
ca-skeleton
feature-webhook-outbound-contract
2026-06-29 2026-06-29

Stripe — Webhook Signatures (공식)

Layer: raw/official-docs/ — Stripe 공식 문서의 원문 발췌 및 출처 기록. Strength 분류: official-vendor-doc — Stripe 공식 개발자 문서 (stripe.com/docs/webhooks/...).

Parent / 활용 branch (필수)

Branch 이 자료가 정당화하는 결정
raw/branch-notes/feature-webhook-outbound-contract D1 (HMAC-SHA256 서명 스키마), D2 (타임스탬프 기반 Replay Attack 방지) 및 secret key rotation 정책 결정 근거.

컨텍스트

feature-webhook-outbound-contract 의 D1, D2 는 아웃바운드 웹훅의 발송자 인증과 리플레이 공격 방지를 위해 헤더 기반 서명 스키마를 수립한다. 본 문서는 Stripe 가 (a) Stripe-Signature 헤더 포맷 (t=timestamp,v1=sig), (b) timestamp + '.' + payload 형태의 서명 조립식, (c) 5분 오차 허용(tolerance window) 리플레이 검증, (d) constant-time byte comparison 을 통한 timing attack 방지, (e) 키 로테이션 시 복수 서명 포함 등을 직접 진술하는 공식 표준 근거이다.

출처 / Source

핵심 인용 / Key quotes (verbatim)

[§Verifying signatures] "Stripe signs the webhook events it sends to your endpoints by including a signature in each event's Stripe-Signature header. This allows you to verify that the events were sent by Stripe, not by a third party."

[§Verifying signatures] "The Stripe-Signature header contains a timestamp and one or more signatures. The timestamp is prefixed by t=, and each signature is prefixed by a scheme. Schemes start with v. Currently, the only supported live signature scheme is v1."

[§Verifying signatures] "Stripe generates the signature using a hash-based message authentication code (HMAC) with SHA-256."

[§Step 1: Extract the timestamp and signatures] "Step 1: Extract the timestamp and signatures: Split the header, using the , character as the separator, to get a list of elements. Then split each element, using the = character as the separator, to get a prefix and value pair."

[§Step 2: Prepare the signed_payload string] "Step 2: Prepare the signed_payload string: Concatenate: The timestamp (as a string), The character ., The actual JSON payload (that is, the request body)"

[§Step 3: Determine the expected signature] "Step 3: Determine the expected signature: Compute an HMAC with the SHA256 hash function. Use the endpoint's signing secret as the key, and the signed_payload string as the message."

[§Step 4: Compare the signatures] "Step 4: Compare the signatures: Compare the signature (or signatures) in the header to the expected signature. To protect against timing attacks, use a constant-time string comparison to compare the expected signature to each of the received signatures."

[§Preventing replay attacks] "A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. To prevent such attacks, Stripe includes a timestamp in the Stripe-Signature header. When verifying signatures, your integration should check that the timestamp is within a tolerance window (defaulting to 5 minutes) of the current time."

[§Preventing replay attacks] "Stripe generates a new signature and timestamp for each retry attempt."

[§Secrets rotation] "If you need to rotate secrets, or if you have multiple active secrets, Stripe includes multiple signatures in the header. For example, if you have two active secrets, the header contains: Stripe-Signature: t=1672531199,v1=sig1,v1=sig2"

Claims Extracted / 추출된 주장

Claim ID Claim (이 자료가 직접 말하는 것) Evidence quote Strength Applies to Does not prove
STRIPE-WEBHOOK-C1 Stripe는 발신자 인증을 위해 모든 웹훅 이벤트의 Stripe-Signature 헤더에 서명을 포함함 "Stripe signs the webhook events it sends to your endpoints by including a signature in each event's Stripe-Signature header." official-vendor-doc 웹훅 발신자 신원 검증 일반 클라이언트-서버 REST API 인증
STRIPE-WEBHOOK-C2 서명 헤더는 타임스탬프(t=)와 서명 리스트(v1=)로 구성되며 쉼표(,)로 구분됨 "The Stripe-Signature header contains a timestamp and one or more signatures. The timestamp is prefixed by t=, and each signature is prefixed by a scheme. Schemes start with v. Currently, the only supported live signature scheme is v1." official-vendor-doc 서명 포맷 파싱 및 결합 구조 JSON 페일로드 이외의 이진 데이터 지원 여부
STRIPE-WEBHOOK-C3 서명 생성에는 해시 기반 메시지 인증 코드인 HMAC-SHA256 알고리즘을 사용함 "Stripe generates the signature using a hash-based message authentication code (HMAC) with SHA-256." official-vendor-doc 암호학적 서명 생성 알고리즘 선택 asymmetric RSA/ECDSA 서명 방식 지원
STRIPE-WEBHOOK-C4 서명 대상 페이로드는 타임스탬프 문자열 + '.' + raw JSON 본문 형태로 조립됨 "Concatenate: The timestamp (as a string), The character ., The actual JSON payload (that is, the request body)" official-vendor-doc 서명 검증 원본 데이터 조립식 페이로드 내 화이트스페이스/개행 문자 무관성
STRIPE-WEBHOOK-C5 서명 생성 시 각 웹훅 엔드포인트별 고유 secret key가 키 값으로 사용됨 "Compute an HMAC with the SHA256 hash function. Use the endpoint's signing secret as the key, and the signed_payload string as the message." official-vendor-doc 비밀 키 범위설정 및 매핑 다중 엔드포인트 간의 단일 마스터 키 사용 방식
STRIPE-WEBHOOK-C6 timing attack을 차단하기 위해 서명 문자열 비교 시 constant-time 비교 방식을 적용해야 함 "Compare the signature (or signatures) in the header to the expected signature. To protect against timing attacks, use a constant-time string comparison to compare the expected signature to each of the received signatures." official-vendor-doc 서명 비교 시 하드웨어 수준 부채널 공격 방어 일반 문자열 equals 비교의 안전성
STRIPE-WEBHOOK-C7 replay attack 방지를 위해 수신단은 타임스탬프와 현재 시각의 오차를 5분 윈도우 내로 제한해야 함 "To prevent such attacks, Stripe includes a timestamp in the Stripe-Signature header. When verifying signatures, your integration should check that the timestamp is within a tolerance window (defaulting to 5 minutes) of the current time." official-vendor-doc 리플레이 공격 방어 윈도우 수립 NTP 비동기화 상태에서의 강제 복구
STRIPE-WEBHOOK-C8 재시도(retry) 발생 시 Stripe는 매번 새로운 타임스탬프와 그에 대응하는 새 서명을 생성하여 발송함 "Stripe generates a new signature and timestamp for each retry attempt." official-vendor-doc 재시도 요청 수신 시 타임스탬프 갱신 정책 수신 측의 재시도 유일성 판별 방법
STRIPE-WEBHOOK-C9 시크릿 로테이션 또는 복수 시크릿 존재 시 헤더에 v1 접두사를 가진 서명이 다중으로 포함됨 "If you need to rotate secrets, or if you have multiple active secrets, Stripe includes multiple signatures in the header." official-vendor-doc 시크릿 로테이션 중단 최소화 설계 특정 서명 매칭 시 다른 서명의 무효화

Usage Boundaries / 적용 경계

  • 이 자료가 직접 증명하는 것:
    • STRIPE-WEBHOOK-C2, C4: 헤더 문자열 포맷(t=...,v1=...) 및 payload 조립 방식 (t.body).
    • STRIPE-WEBHOOK-C3, C5: HMAC-SHA256 알고리즘 사용과 엔드포인트별 단일 secret mapping.
    • STRIPE-WEBHOOK-C6: constant-time comparison (MessageDigest.isEqual) 필수 적용.
    • STRIPE-WEBHOOK-C7: replay window 기본값 5분 (300초).
    • STRIPE-WEBHOOK-C9: 로테이션 단계에서 다중 signature 전송 메커니즘 지원.
  • 이 자료가 증명하지 않는 것:
    • 수신단 시스템 시각 보정 (NTP) — 수신 서버의 NTP 동기화가 실패하여 발생하는 타임스탬프 불일치 예외 처리 흐름은 명시하지 않음.
    • DB 기반 Key-Rotation 스키마 — 복수 Active Secret을 보관하기 위한 데이터베이스 테이블 구조 및 캐싱 메커니즘은 증명하지 않음.
    • 서명 해시 인코딩 포맷 — 본문에는 명시되지 않았으나 관례적으로 HMAC 결과값을 Hexadecimal(16진수) 문자열로 인코딩하여 매칭한다는 점.
  • 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
    • Spring Core RestClient를 활용해 외부 요청을 보낼 때, 직렬화된 JSON payload의 바이트 배열이 변경(예: Jackson Indent 출력, UTF-8 외 인코딩)되면 서명이 깨지므로, 반드시 JSON 직렬화 직후의 raw byte array를 그대로 서명 계산에 투입해야 함.
    • 다중 Secret을 지원하기 위해 application.yml 및 Database 구조가 List 형태의 Secret Key를 매핑할 수 있도록 설계되어야 함.

메모 / Notes

  • Constant-time comparison: Java에서는 java.security.MessageDigest.isEqual(byte[], byte[])가 constant-time 비교를 제공하므로 이를 서명 검증 유틸에 필수로 사용해야 함.
  • Header Parsing: 쉼표로 파싱할 때 t=1672531199v1=sig1을 각각 맵핑하고, 서명 목록(List<String>)과 단일 타임스탬프(String)로 분리해 내는 견고한 파서 필요.
  • Rotation Window: overlap-24h 또는 manual 로테이션 시 120초~300초 간 복수 서명이 발송될 수 있으므로, 수신 측은 목록 중 하나라도 일치하면 성공으로 판정해야 함.