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를 그대로 넘길 수 있습니다. 헤더 값 자체를 넘겨도 됩니다.
도착한 그대로의 원본 본문을 전달하세요. 파싱한 뒤 다시 인코딩한 본문은 더 이상 서명과 일치하지 않습니다.
오래된 전달
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 상태로 응답하세요. 다른 응답을 받은 전달은 나중에 다시 시도됩니다.