본문 바로가기

로딩 중...


HMAC 생성기

쇼핑몰 결제 시스템을 붙이면서 결제사에서 웹훅이 날아오기 시작했습니다. 그런데 이게 정말 결제사가 보낸 건지, 누가 결제 완료 요청을 흉내 내서 쏜 건지 서버 입장에선 구분할 방법이 없더군요. 결제사 문서를 보니 요청 헤더에 서명값이 같이 오고, "우리가 알려준 시크릿 키로 본문을 HMAC-SHA256 해서 이 값과 같으면 진짜"라고 적혀 있었습니다. HMAC 생성기는 그 서명값을 직접 만들어 보고, 서버가 계산한 값과 결제사가 보낸 값이 정말 일치하는지 브라우저에서 바로 대조해 보는 도구입니다.

처음엔 서명 검증 코드가 왜 자꾸 MISMATCH가 나는지 몰라 며칠을 헤맸습니다. 알고 보니 본문 끝에 줄바꿈 하나가 더 붙어 있었던 게 원인이었죠. 그 삽질을 다시 하기 싫어서, 메시지와 키를 넣으면 서명값과 함께 바이트 수·숨은 줄바꿈까지 보여 주도록 만들었습니다.

사용 방법

  1. 위쪽 큰 입력창에 서명할 메시지를 붙여넣고, 아래 칸에 시크릿 키를 입력합니다. 키가 Text가 아니라 HexBase64 형태라면 키 칸 왼쪽 토글로 형식을 먼저 맞춰 주세요. 감이 안 잡히면 샘플 버튼으로 예시부터 채워 봐도 됩니다.

    HMAC 생성기-guide-1

  2. 알고리즘 드롭다운에서 해시 방식을 고릅니다. 결제·API 서명은 대부분 SHA256이라 기본값이 그걸로 잡혀 있고, 그 밖에 SHA1·SHA224·SHA384·SHA512, MD4·MD5, RIPEMD160, DES 계열과 RC2까지 고를 수 있습니다.

    HMAC 생성기-guide-2

  3. 포맷에서 HEXBASE64 중 상대 시스템이 요구하는 출력 형식을 고른 뒤 Convert를 누르면 서명값이 나옵니다. 검증할 서명이 이미 있다면 오른쪽 비교할 서명을 붙여넣으세요 칸에 넣어 두세요. 계산 결과와 같으면 MATCH, 다르면 MISMATCH가 바로 뜹니다.

    HMAC 생성기-guide-3

HMAC은 왜, 어떻게 만들어졌나

그냥 SHA256으로 본문을 해시하면 안 되냐고 생각하기 쉽습니다. 문제는 SHA256 같은 일반 해시엔 비밀이 없다는 점입니다. 알고리즘이 공개돼 있으니 누구나 아무 메시지나 해시할 수 있고, 그래서 "이 해시값을 계산한 게 나뿐"이라는 증명이 안 됩니다. 위조하는 쪽도 똑같이 본문을 바꾸고 새 해시를 붙이면 그만이니까요.

HMAC은 여기에 비밀키를 섞습니다. 나와 상대만 아는 키를 정해진 방식으로 메시지와 함께 해싱해서, "이 서명은 키를 아는 쪽이 만들었다"를 증명하는 겁니다. 키를 모르면 같은 서명값을 만들어 낼 수 없으니, 서명이 맞다는 건 곧 발신자가 진짜라는 뜻이 되죠. 이 방식을 정리한 게 RFC 2104이고, 그래서 HMAC-SHA256처럼 뒤에 붙는 이름은 "어떤 해시 함수를 안에 넣었나"를 가리킵니다.

HMAC이면 무조건 안전할까

아닙니다. HMAC의 안전성은 전부 비밀키가 새지 않는다는 전제 위에 서 있습니다. 키가 깃허브에 커밋되거나 로그에 찍히는 순간, 누구든 유효한 서명을 만들어 낼 수 있으니 그때부턴 서명이 아무것도 증명하지 못합니다.

검증하는 코드 쪽도 함정이 있습니다. 계산한 서명과 받은 서명을 ==로 앞에서부터 한 글자씩 비교하면, 틀린 위치에 따라 응답 시간이 미세하게 달라지고 공격자가 그 차이를 재서 서명을 한 바이트씩 맞춰 갈 수 있습니다. 타이밍 공격이라고 부르는데, 그래서 실제 검증에는 crypto.timingSafeEqual 같은 상수 시간 비교를 써야 합니다. 이 도구의 MATCH/MISMATCH는 사람이 눈으로 값을 맞춰 보는 용도지, 서버 검증 로직을 대신하는 게 아닙니다.

HMAC이 실제로 필요한 사례들

가장 흔한 게 결제·배송 같은 웹훅 검증입니다. 남의 서버로 날아온 요청이 진짜 그 업체가 보낸 건지 확인해야 하니, 업체가 준 시크릿 키로 본문을 HMAC 해서 요청에 딸려 온 서명과 맞춰 봅니다. API 요청 서명도 같은 원리라, 클라이언트가 요청 내용을 키로 서명해 보내면 서버가 다시 계산해 위변조를 잡아냅니다. 세션 토큰이나 쿠키에 서명을 붙여 사용자가 값을 몰래 고치지 못하게 막을 때도 HMAC이 쓰입니다.

이 도구를 서명 디버깅에 쓸 때 진짜 유용한 건 서명값 아래 슬쩍 나오는 정보입니다. 메시지 바이트 수, 키 바이트 수를 보여 주고, 본문에 CRLF 줄바꿈이나 끝에 붙은 개행, BOM, 앞뒤 공백이 있으면 경고로 알려 줍니다. 서명이 자꾸 안 맞을 때 열에 아홉은 알고리즘이 아니라 이런 눈에 안 보이는 한 바이트가 범인입니다. 내 서버가 서명하는 원문과 여기 붙여넣은 원문의 바이트 수부터 맞춰 보면, 어디서 어긋났는지가 대개 거기서 드러납니다.

자주 묻는 질문

HMAC과 일반 해시의 차이가 뭔가요?

일반 해시 H(message)는 메��지만 알면 누구나 계산할 수 있지만, HMAC은 비밀 키(Secret Key)를 함께 사용하여 키를 모르는 사람은 올바른 값을 생성할 수 없습니다. 이를 통해 메시지의 무결성(변조 여부)과 인증(발신자 확인)을 동시에 보장합니다.

Webhook 서명 검증에 HMAC을 어떻게 활용하나요?

GitHub, Stripe, Slack 등의 서비스는 Webhook 요청 시 헤더에 HMAC 서명을 포함합니다. 예를 들어 GitHub은 X-Hub-Signature-256 헤더에 HMAC-SHA256(secret, body) 값을 전달합니다. 수신 서버에서 동일한 방식으로 계산한 값과 비교하여 요청이 해당 서비스에서 온 것인지 검증합니다.

HMAC 키의 권장 길이는 얼마인가요?

HMAC 키는 최소한 사용하는 해시 함수의 출력 길이 이상이어야 합니다. HMAC-SHA256이면 32바이트(256비트) 이상, HMAC-SHA512이면 64바이트(512비트) 이상을 권장합니다. 충분히 무작위한 값으로 생성해야 하며, 예측 가능한 문자열은 사용하지 마세요.

비밀 키가 서버로 전송되나요?

아니요, 이 도구는 Web Crypto API를 사용하여 브라우저 내에서 모든 HMAC 연산을 수행합니다. 입력한 메시지와 비밀 키는 외부 서버로 전송되지 않으므로 안심하고 사용할 수 있습니다.

Timing Attack이 뭔가요?

HMAC 검증 시 일반 문자열 비교(===)를 사용하면, 불일치 위치에 따라 응답 시간이 미세하게 달라집니다. 공격자가 이 시간 차이를 분석하여 한 바이트씩 올바른 HMAC 값을 추측할 수 있으며, 이를 Timing Attack이라 합니다. 서버 측 검증에서는 반드시 상수 시간 비교(Constant-time comparison)를 사용해야 합니다.