문서로 건너뛰기
Java

웹훅 검증

전달의 내용을 신뢰하기 전에 서명을 확인하세요.

전달 검증하기

WebhookHandler.java
import com.sun.net.httpserver.HttpExchange;import com.sun.net.httpserver.HttpHandler;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.Map;import uk.openemail.OpenEmail;import uk.openemail.exception.WebhookSignatureException; public final class WebhookHandler implements HttpHandler {    @Override    public void handle(HttpExchange exchange) throws IOException {        String rawBody = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);        String secret = System.getenv("OPENEMAIL_WEBHOOK_SECRET");        int status = 204;         try {            Map<String, Object> event = OpenEmail.verifyWebhookSignature(rawBody, exchange.getRequestHeaders(), secret);             System.out.println(event.get("type") + " " + event.get("id"));        } catch (WebhookSignatureException error) {            status = 400;        }         exchange.sendResponseHeaders(status, -1);        exchange.close();    }}

OpenEmail.verifyWebhookSignature는 X-OpenEmail-Signature 헤더를 읽고, 타임스탬프와 본문에 대한 HMAC을 상수 시간으로 확인한 뒤 이벤트를 Map<String, Object>로 반환합니다. 시크릿은 client.webhooks().create가 반환한 값입니다.

헤더는 이름의 대소문자를 가리지 않고 값이 텍스트 또는 텍스트 목록인 map입니다. 그래서 exchange.getRequestHeaders()와 Spring의 HttpHeaders를 그대로 넘길 수 있습니다. 헤더 값 자체를 넘겨도 됩니다.

도착한 그대로의 원본 본문을 전달하세요. 파싱한 뒤 다시 인코딩한 본문은 더 이상 서명과 일치하지 않습니다.

오래된 전달

Tolerance.java
String signature = "t=1767225600,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd";Map<String, String> headers = Map.of("X-OpenEmail-Signature", signature); try {    OpenEmail.verifyWebhookSignature("{}", headers, System.getenv("OPENEMAIL_WEBHOOK_SECRET"), Duration.ofMinutes(1));} catch (WebhookSignatureException error) {    System.err.println(error.getMessage());}

5분보다 오래된 전달은 거부되므로, 가로챈 요청을 나중에 재전송할 수 없습니다. 마지막 인수로 Duration을 주면 이 5분을 바꿀 수 있고, Duration.ZERO이면 얼마나 오래된 전달이든 받습니다.

  • 헤더가 없거나 형식이 잘못된 경우, 서명이 일치하지 않는 경우, 전달이 너무 오래된 경우 모두 WebhookSignatureException을 던집니다.
  • 시크릿을 교체한 뒤에는 전달에 서명이 둘 이상 붙을 수 있으며, 그중 하나만 일치하면 통과합니다.
  • 빠르게 2xx 상태로 응답하세요. 다른 응답을 받은 전달은 나중에 다시 시도됩니다.