HMAC 생성기 · 웹훅 서명 검증

HMAC-SHA256, SHA-512, SHA-1, MD5를 브라우저에서 계산합니다. 키는 텍스트·16진수·Base64를 지원하고, 네이버 클라우드 API 서명과 GitHub·Stripe 웹훅 서명을 대조해 불일치 원인을 알려 줍니다.

  • 브라우저에서 처리
  • 데이터가 브라우저 밖으로 나가지 않습니다
  • 무료 · 회원가입 불필요
'직접 입력 HMAC'은 아무 키와 메시지로 계산하고 알고리즘도 고를 수 있습니다. 다른 형식은 각 서비스 문서대로 서명 대상 문자열을 만들고, 알고리즘을 고정하고, 그 서비스가 쓰는 헤더나 파라미터 모양으로 '보낼 값' 줄을 추가합니다. Feishu, DingTalk, 네이버 클라우드는 내가 보내는 요청에 서명하는 형식이라 본문 입력 칸이 없습니다. '예시'는 공식 문서에 실린 테스트 데이터를 채웁니다. 데이터가 있는 형식에서만 보입니다.
비트 HMAC의 왼쪽부터 지정한 비트만 남깁니다(RFC 2104 §5). 세 가지 표기에 모두 적용됩니다. 8의 배수로, 8부터 전체 길이까지 입력합니다. 비워 두면 전체 길이입니다. 출력의 절반보다 짧거나 80비트보다 짧으면 안내가 나옵니다. '직접 입력 HMAC'에서만 쓸 수 있습니다.

서명할 바이트입니다. '직접 입력 HMAC'에서는 텍스트(UTF-8로 인코딩), 16진수, Base64 중에서 고릅니다. 다른 형식은 받은 요청 본문을 텍스트로 다룹니다. 텍스트 칸의 줄바꿈은 모두 LF가 되므로, 보낸 쪽이 CRLF를 썼다면 CRLF를 고르세요. 16진수에는 공백, 콜론, 앞의 0x가 있어도 됩니다. Base64는 표준 문자와 URL 안전 문자 모두, 패딩이 있든 없든 읽습니다. 16진수와 Base64에서는 입력기로 들어간 전각 문자를 반각으로 읽습니다. EUC-KR, Shift_JIS, GBK 텍스트는 16진수로 붙여 넣으세요.
'직접 입력 HMAC'에서는 키를 텍스트(UTF-8), 16진수, Base64 중에서 고릅니다. 다른 형식은 각 서비스 규칙대로 읽습니다. 대부분 텍스트 그대로 쓰고(Stripe는 whsec_ 접두사까지 포함), Chatwork는 Base64로 디코딩하고, Standard Webhooks는 whsec_ 뒤의 부분을 Base64로 디코딩합니다. 키가 해시 블록 길이(64바이트, SHA-384와 SHA-512는 128바이트)보다 길면 HMAC이 먼저 키를 해시하고, 짧으면 0으로 채웁니다(RFC 2104). 블록보다 긴 키와 출력보다 짧은 키에는 안내가 나옵니다. 텍스트 키의 앞뒤 공백도 키에 포함됩니다.
결과 입력하는 대로 바뀝니다. Hex, Base64, Base64url은 같은 바이트를 세 가지로 적은 것입니다. 서비스 형식에서 추가되는 '보낼 값'은 그 서비스가 실제로 쓰는 헤더나 파라미터 모양입니다. '서명 대상 문자열'은 HMAC에 들어간 문자열 그대로이며, 줄바꿈과 탭을 기호로 보여 줍니다. 도구 안에 포커스가 있을 때 Ctrl+L(Mac은 ⌘+L)을 누르면 텍스트 칸을 비웁니다.

키나 메시지를 입력하면 여기에 HMAC이 표시됩니다.

받은 서명을 붙여 넣습니다. sha256=…, t=…,v1=…, v1,… 같은 헤더, sign=…이 들어 있는 DingTalk URL, 16진수나 Base64 값만 넣어도 읽습니다. 바이트로 비교하므로 16진수(대문자든 소문자든)와 Base64 모두 됩니다. 잘린 값은 10바이트 이상이면 앞부분 일치로 판정합니다. 일치하지 않으면 흔한 원인(끝의 줄바꿈, CRLF, 앞뒤 공백, JSON 재정렬, 키 인코딩, 키와 메시지 뒤바뀜, 다른 알고리즘)을 하나씩 시험해, 붙여 넣은 값이 나오는 첫 원인을 알려 줍니다. 서버에서는 상수 시간으로 비교하세요.

키, 메시지, 서명은 이 탭 안에서 Web Crypto API로 계산합니다. 전송하거나 저장하지 않으며, 새로 고치면 사라집니다.

자세한 가이드 읽기 HMAC-SHA256 완전 가이드: 원리·Webhook 서명 검증·온라인 생성
예시·자세한 설명·자주 묻는 질문 실제 출력이 있는 예시, 다른 도구와의 차이, 자주 묻는 질문.

계산은 RFC 2104 정의를 따릅니다. 키가 블록 길이(SHA-256은 64바이트, SHA-512는 128바이트)보다 길면 먼저 해시하고, 출력보다 짧은 키에는 안내를 띄웁니다(RFC 2104 §3은 권하지 않습니다). ‘자르기’는 RFC 2104 §5처럼 왼쪽부터 지정한 비트만 남깁니다.

네이버 클라우드 API 서명 만들기

네이버 클라우드 플랫폼의 Ncloud API 공통 가이드는 x-ncp-apigw-signature-v2를 이렇게 만들라고 합니다. 메서드 + 공백 + URL(쿼리 포함) + \n + 타임스탬프 + \n + Access Key를 Secret Key로 HmacSHA256 계산한 뒤 Base64로 인코딩합니다. 타임스탬프는 밀리초이고 API Gateway와 5분 이상 차이 나면 요청이 무효가 됩니다.

가이드 예시 경로 /photos/puppy.jpg?query1=&query2에, 실제 키 대신 자리표시자 ACCESS_KEY_ID와 SECRET_KEY, 타임스탬프 1700000000000을 넣으면 서명 대상과 결과는 다음과 같습니다.

GET /photos/puppy.jpg?query1=&query2
1700000000000
ACCESS_KEY_ID

x-ncp-apigw-signature-v2: J5srbJYp9CF97yrUxy0xTrvRQBv9R8ORkITTlii4xxQ=

서명 대상 칸은 줄바꿈을 ␊로 표시하므로, 코드에서 \n 대신 \r\n이나 공백을 넣었는지 바로 보입니다. 시계 확인용 ‘현재 시각’ 버튼은 밀리초 타임스탬프를 넣고, 10자리(초)를 넣으면 밀리초가 아니라고 알려 줍니다.

웹훅 서명 대조하기

GitHub의 웹훅 전송 검증 문서에는 시크릿 It's a Secret to Everybody, 페이로드 Hello, World!, 기대 서명이 실려 있습니다. 형식을 GitHub 웹훅으로 두고 ‘예시’를 누르면 같은 값이 나옵니다.

X-Hub-Signature-256: sha256=757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17

본문을 터미널에서 복사하다 끝에 줄바꿈이 붙으면 결과가 8fde2e97…로 바뀝니다. 이때 원래 헤더를 붙여 넣으면 ‘끝의 줄바꿈을 지우면 일치합니다’라고 원인을 알려 줍니다. Stripe의 t=…,v1=…처럼 서명이 여러 개 들어 있는 헤더는 그중 몇 번째가 일치했는지 표시합니다.

EUC-KR 문자열에 서명할 때

텍스트는 UTF-8 바이트로 바꿔 계산합니다. ‘서명’은 UTF-8로 6바이트, EUC-KR로는 bcadb8ed 4바이트입니다. 키 key로 계산하면 결과가 다릅니다.

UTF-8: cd59f4fe8cbf9974711c276d64763113446368400791e903ac9d1568fede639c

EUC-KR(메시지 형식을 16진수로 하고 bcadb8ed): d376b8c6812d18fda0d71f78b457195358b17786874e8146c98a19165bb3a0e7

오래된 연동 규격이 EUC-KR 기준이라면 16진수로 바꿔 넣으세요.

다른 HMAC 도구와의 차이

2026-10-01에 GitHub 문서 예시로 확인했습니다. 툴타다는 브라우저에서 계산하지만, 키를 ‘Hex (16진수)‘로 두고 0b0g나 홀수 자리 abc를 넣어도 오류 없이 결과를 냅니다. 확인해 보니 그 값은 키를 텍스트로 읽은 HMAC이었습니다. Go Tools는 검증 탭이 있지만 헤더 그대로의 sha256=757107ea…는 ‘일치하지 않음’으로 판정하고, 본문 끝에 줄바꿈이 붙은 경우에도 불일치만 알려 줍니다. 이 도구는 16진수·Base64 오류를 몇 번째 문자인지 알려 주고, 헤더 접두사를 읽으며, 불일치하면 가능한 원인을 찾아 줍니다.

제한 사항

  • 알고리즘은 MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512입니다. SHA-3와 RIPEMD-160은 Web Crypto API에 없어 지원하지 않습니다.
  • 텍스트 칸의 줄바꿈은 모두 LF가 됩니다. CRLF로 서명했다면 줄바꿈을 CRLF로 바꾸고, 그 밖의 특수한 바이트는 16진수나 Base64로 넣으세요.
  • 브라우저 안의 대조는 디버깅용입니다. 서버에서는 받은 본문 바이트를 그대로 쓰고 상수 시간으로 비교하세요. JWT의 HS256도 HMAC-SHA256이므로 JWT 생성기에서 다룰 수 있습니다.

키 없는 해시는 해시 생성기, HMAC-SHA1로 만드는 일회용 코드는 2FA 코드 생성기를 쓰세요.

FAQ

비밀 키가 전송되거나 저장되나요?

아니요. SHA-1, SHA-256, SHA-384, SHA-512는 브라우저의 Web Crypto API로, MD5와 SHA-224는 페이지 안의 코드로 계산합니다. 네트워크 요청을 보내지 않고 키와 메시지를 localStorage, 쿠키, URL에 쓰지 않습니다. 이 페이지는 분석이나 광고 스크립트도 불러오지 않습니다. 새로 고치면 입력이 모두 지워집니다.

네이버 클라우드 API 서명이 맞지 않아요.

서명 대상은 메서드, 공백, 경로와 쿼리 문자열, 줄바꿈, 타임스탬프(밀리초), 줄바꿈, Access Key ID 순서입니다. 쿼리 문자열을 빠뜨리거나, 헤더의 x-ncp-apigw-timestamp와 서명에 쓴 타임스탬프가 다르거나, 5분 넘게 시계가 어긋나면 실패합니다. 형식에서 네이버 클라우드 API를 고르면 서명 대상 문자열을 줄바꿈 표시와 함께 보여 줍니다.

웹훅 서명이 일치하지 않는 흔한 원인은?

대부분 계산한 바이트가 보낸 쪽과 다릅니다. 본문을 JSON으로 파싱한 뒤 다시 직렬화했거나, 끝의 줄바꿈이 붙거나 빠졌거나, 줄바꿈이 LF와 CRLF 사이에서 바뀌었거나, 타임스탬프나 접두사를 서명 대상에 넣지 않은 경우입니다. 받은 서명을 '대조할 서명'에 붙여 넣으면 이런 경우를 차례로 시험해 원인을 알려 줍니다.

어떤 알고리즘을 골라야 하나요?

상대 쪽 규격을 따르세요. 새로 설계한다면 HMAC-SHA256이 일반적이며 네이버 클라우드 API, GitHub, Stripe, Slack, LINE이 이를 씁니다. HMAC-SHA1은 Twilio와 GitHub의 구 헤더 X-Hub-Signature, HMAC-MD5는 오래된 시스템과 RFC 2104 테스트 벡터를 위해 있습니다.

서버에서 서명을 ==로 비교해도 되나요?

피하세요. Java의 MessageDigest.isEqual, Node.js의 crypto.timingSafeEqual(길이가 다르면 예외가 나므로 길이부터 비교), Python의 hmac.compare_digest, Go의 hmac.Equal처럼 상수 시간 비교를 쓰세요. 이 도구의 대조는 브라우저 안에서만 하므로 시간 차는 문제가 되지 않습니다.