HMAC 생성기
쇼핑몰 결제 시스템을 붙이면서 결제사에서 웹훅이 날아오기 시작했습니다. 그런데 이게 정말 결제사가 보낸 건지, 누가 결제 완료 요청을 흉내 내서 쏜 건지 서버 입장에선 구분할 방법이 없더군요. 결제사 문서를 보니 요청 헤더에 서명값이 같이 오고, "우리가 알려준 시크릿 키로 본문을 HMAC-SHA256 해서 이 값과 같으면 진짜"라고 적혀 있었습니다. HMAC 생성기는 그 서명값을 직접 만들어 보고, 서버가 계산한 값과 결제사가 보낸 값이 정말 일치하는지 브라우저에서 바로 대조해 보는 도구입니다.
처음엔 서명 검증 코드가 왜 자꾸 MISMATCH가 나는지 몰라 며칠을 헤맸습니다. 알고 보니 본문 끝에 줄바꿈 하나가 더 붙어 있었던 게 원인이었죠. 그 삽질을 다시 하기 싫어서, 메시지와 키를 넣으면 서명값과 함께 바이트 수·숨은 줄바꿈까지 보여 주도록 만들었습니다.
사용 방법
-
위쪽 큰 입력창에 서명할 메시지를 붙여넣고, 아래 키 칸에 시크릿 키를 입력합니다. 키가 Text가 아니라 Hex나 Base64 형태라면 키 칸 왼쪽 토글로 형식을 먼저 맞춰 주세요. 감이 안 잡히면 샘플 버튼으로 예시부터 채워 봐도 됩니다.

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

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

HMAC은 왜, 어떻게 만들어졌나
그냥 SHA256으로 본문을 해시하면 안 되냐고 생각하기 쉽습니다. 문제는 SHA256 같은 일반 해시엔 비밀이 없다는 점입니다. 알고리즘이 공개돼 있으니 누구나 아무 메시지나 해시할 수 있고, 그래서 "이 해시값을 계산한 게 나뿐"이라는 증명이 안 됩니다. 위조하는 쪽도 똑같이 본문을 바꾸고 새 해시를 붙이면 그만이니까요.
HMAC은 여기에 비밀키를 섞습니다. 나와 상대만 아는 키를 정해진 방식으로 메시지와 함께 해싱해서, "이 서명은 키를 아는 쪽이 만들었다"를 증명하는 겁니다. 키를 모르면 같은 서명값을 만들어 낼 수 없으니, 서명이 맞다는 건 곧 발신자가 진짜라는 뜻이 되죠. 이 방식을 정리한 게 RFC 2104이고, 그래서 HMAC-SHA256처럼 뒤에 붙는 이름은 "어떤 해시 함수를 안에 넣었나"를 가리킵니다.
HMAC이면 무조건 안전할까
아닙니다. HMAC의 안전성은 전부 비밀키가 새지 않는다는 전제 위에 서 있습니다. 키가 깃허브에 커밋되거나 로그에 찍히는 순간, 누구든 유효한 서명을 만들어 낼 수 있으니 그때부턴 서명이 아무것도 증명하지 못합니다.
검증하는 코드 쪽도 함정이 있습니다. 계산한 서명과 받은 서명을 ==로 앞에서부터 한 글자씩 비교하면, 틀린 위치에 따라 응답 시간이 미세하게 달라지고 공격자가 그 차이를 재서 서명을 한 바이트씩 맞춰 갈 수 있습니다. 타이밍 공격이라고 부르는데, 그래서 실제 검증에는 crypto.timingSafeEqual 같은 상수 시간 비교를 써야 합니다. 이 도구의 MATCH/MISMATCH는 사람이 눈으로 값을 맞춰 보는 용도지, 서버 검증 로직을 대신하는 게 아닙니다.
HMAC이 실제로 필요한 사례들
가장 흔한 게 결제·배송 같은 웹훅 검증입니다. 남의 서버로 날아온 요청이 진짜 그 업체가 보낸 건지 확인해야 하니, 업체가 준 시크릿 키로 본문을 HMAC 해서 요청에 딸려 온 서명과 맞춰 봅니다. API 요청 서명도 같은 원리라, 클라이언트가 요청 내용을 키로 서명해 보내면 서버가 다시 계산해 위변조를 잡아냅니다. 세션 토큰이나 쿠키에 서명을 붙여 사용자가 값을 몰래 고치지 못하게 막을 때도 HMAC이 쓰입니다.
이 도구를 서명 디버깅에 쓸 때 진짜 유용한 건 서명값 아래 슬쩍 나오는 정보입니다. 메시지 바이트 수, 키 바이트 수를 보여 주고, 본문에 CRLF 줄바꿈이나 끝에 붙은 개행, BOM, 앞뒤 공백이 있으면 경고로 알려 줍니다. 서명이 자꾸 안 맞을 때 열에 아홉은 알고리즘이 아니라 이런 눈에 안 보이는 한 바이트가 범인입니다. 내 서버가 서명하는 원문과 여기 붙여넣은 원문의 바이트 수부터 맞춰 보면, 어디서 어긋났는지가 대개 거기서 드러납니다.