해시·HMAC 생성기

MD5취약
SHA-1취약
SHA-256
SHA-512

MD5와 SHA-1은 취약하므로 비밀번호나 서명에 사용해서는 안 됩니다. 체크섬이나 캐시 키 용도로는 여전히 적합합니다.

입력한 내용은 저장, 기록, 공유되지 않습니다.

텍스트를 입력하면 MD5, SHA-1, SHA-256, SHA-512 해시를 한 번에 보여줍니다. HMAC 모드에서는 비밀 키로 서명할 수 있습니다. 모든 처리가 브라우저에서 이루어지므로 텍스트와 키 모두 기기를 벗어나지 않습니다.

사용 방법

  1. 입력창에 텍스트를 붙여넣습니다.
  2. 입력하는 동안 네 가지 해시가 계산됩니다.
  3. 옆의 버튼으로 원하는 해시를 복사합니다.

해시가 보장하는 것

암호학적 해시는 길이에 상관없이 입력을 고정 크기의 다이제스트로 결정적으로 변환합니다. 같은 바이트는 항상 같은 결과를 내고, 비트 하나만 바꿔도 출력의 약 절반이 바뀝니다. 해시를 쓸모 있게 만드는 성질은 세 가지이며, 용도마다 필요한 성질이 다릅니다.

역상 저항성은 다이제스트가 주어졌을 때 그것을 만드는 입력을 찾을 수 없다는 뜻입니다. 제2 역상 저항성은 입력 하나가 주어졌을 때 같은 다이제스트를 갖는 다른 입력을 찾을 수 없다는 뜻입니다. 충돌 저항성은 충돌하는 두 입력을 어떤 것이든 찾을 수 없다는 뜻인데, 공격자가 양쪽을 모두 고를 수 있으므로 셋 중 가장 공격하기 쉽습니다.

이 마지막 차이 때문에 깨진 알고리즘이라도 모든 용도에서 똑같이 위험하지는 않습니다. MD5 충돌은 몇 초 만에 만들 수 있지만 MD5 다이제스트를 역산할 수 있는 사람은 없습니다. 그래서 캐시 키나 악의적인 상황을 가정하지 않는 체크섬으로 MD5를 쓰는 것은 괜찮지만, 서명으로 쓰는 것은 안 됩니다.

알고리즘별 현황

MD5는 2004년부터 깨진 것으로 간주되어 왔고, 공격자가 의미가 다른 두 문서를 같은 해시가 되도록 만드는 선택 접두사 충돌도 이제는 저렴하게 가능합니다. 2008년에는 실제로 작동하는 인증 기관을 위조하는 데, 2012년에는 Flame 악성코드에 쓰였습니다. 체크섬, ETag, 캐시 키에는 써도 되지만, 공격자가 무너뜨려서 이득을 볼 수 있는 곳에는 절대 쓰지 마세요.

SHA-1도 뒤를 이었습니다. 2017년에 두 개의 PDF로 첫 실용적 충돌이 시연되었고, 2020년에는 수만 달러의 비용으로 선택 접두사 충돌이 실현되었습니다. 브라우저는 수년 전에 SHA-1 인증서를 받아들이지 않게 되었고, Git도 SHA-1에서 벗어나는 중입니다. 조금 더 오래 버틴 MD5로 취급하세요.

SHA-256과 SHA-512가 현재의 기본값이며 알려진 실용적 약점이 없습니다. 둘 다 SHA-2 계열이고, SHA-512는 출력이 더 길지만 64비트 하드웨어에서는 오히려 더 빠른 경우가 많습니다. SHA-3는 대체재라기보다 구조가 다른 예비용으로 존재하며, 큰 파일에서 속도가 중요하다면 BLAKE3도 알아 둘 만합니다.

HMAC, 그리고 키와 메시지를 그냥 함께 해시하면 안 되는 이유

일반 해시는 누구나 계산할 수 있으므로 누가 만들었는지에 대해 아무것도 증명하지 못합니다. HMAC은 비밀 키를 더하므로, 다이제스트가 일치하면 보낸 쪽이 키를 알고 있고 메시지가 변조되지 않았음을 보여 줍니다. Stripe, GitHub 등 여러 서비스의 웹훅 전송 서명과 AWS API 요청 인증이 바로 이것으로 이루어집니다.

직관적인 방식, 즉 키 뒤에 메시지를 붙여 해시하는 방법은 SHA-2 계열에서 안전하지 않습니다. 이들은 Merkle-Damgård 구조의 함수이고 다이제스트가 곧 내부 상태 전체이기 때문입니다. 유효한 다이제스트 하나를 가진 공격자는 그 상태에서 이어서 데이터를 덧붙여, 키를 전혀 모르는 채로 더 긴 메시지에 대한 유효한 다이제스트를 만들 수 있습니다. 두 개의 파생 키로 두 번 해시하는 HMAC의 중첩 구조가 이를 막아 줍니다.

검증할 때 꼭 지켜야 할 것이 하나 있습니다. 다이제스트는 상수 시간으로 비교해야 합니다. 일반 문자열 비교는 차이를 발견하는 즉시 반환하며, 요청이 충분히 쌓이면 그 시간 차이를 측정할 수 있어 공격자가 서명을 한 바이트씩 알아낼 수 있습니다. 대부분의 언어가 이를 위한 전용 함수를 제공합니다.

해시는 암호화도, 비밀번호 저장 방식도 아니다

해시는 단방향이고 키가 없습니다. 복호화할 것도 없고 입력을 되찾을 방법도 없습니다. 데이터를 되돌려야 한다면 필요한 것은 완전히 다른 도구인 암호화입니다.

비밀번호에 빠른 해시를 쓰는 것은 정확히 잘못된 선택입니다. 속도는 공격자에게 유리합니다. 일반 소비자용 하드웨어로도 유출된 데이터베이스에 대해 초당 수십억 번의 SHA-256 추측을 시도할 수 있고, 솔트가 없는 다이제스트는 미리 계산한 테이블에서 바로 찾아낼 수 있습니다. 비밀번호 저장에는 일부러 느리고 메모리를 많이 쓰는 함수를 비밀번호별 솔트와 함께 써야 합니다. bcrypt, scrypt, 그리고 현재 권장되는 Argon2id가 있습니다.

좀 더 미묘한 오용도 짚어 둘 만합니다. 식별자를 익명화하려고 해시하는 것입니다. 이메일 주소나 전화번호를 해시해도 아무것도 보호되지 않습니다. 가능한 입력의 범위가 모두 나열할 수 있을 만큼 작기 때문입니다. 다이제스트를 가진 사람은 보유한 모든 주소를 해시해 대조할 수 있습니다. 엔트로피가 낮은 값의 해시는 익명화가 아니라 조회 키일 뿐입니다.

다운로드 파일을 단계별로 검증하기

공개된 체크섬은 한 가지 질문에만 답합니다. 내가 받은 바이트가 배포자가 가지고 있던 바이트와 같은가 하는 것입니다. 파일을 로컬에서 해시하고 - macOS에서는 shasum -a 256 file.iso, 리눅스에서는 sha256sum, PowerShell에서는 Get-FileHash - 다운로드 페이지에 적힌 다이제스트와 비교합니다. 한 글자만 달라도 그 파일은 같은 파일이 아닙니다.

이 비교가 알려 주지 못하는 것은 배포자의 페이지 자체가 진짜인지 여부입니다. 공격자가 다운로드 파일을 바꿀 수 있다면 대개 그 옆의 체크섬도 바꿀 수 있습니다. 진지한 프로젝트가 다이제스트만 올리지 않고 체크섬 파일에 GPG 키로 서명하는 이유가 여기에 있습니다. 서명을 먼저 검증하고 그다음 체크섬을 검증하는 이 연결 고리가 있어야 비로소 무언가가 증명됩니다.

같은 이유로 MD5는 적대적인 상황이 아닌 곳에서 체크섬으로는 여전히 쓸 만하지만 서명으로는 쓸 수 없습니다. 손상된 다운로드를 잡아내는 데에는 MD5로 충분합니다. 그러나 두 파일이 같은 다이제스트를 갖게 만들려는 상대 앞에서는 2004년부터 이미 깨져 있습니다.

해시는 검사 수단이자 주소

오늘날 인프라의 상당 부분은 콘텐츠를 이름이 아니라 해시로 식별합니다. Git은 모든 객체를 그 내용의 다이제스트로 이름 붙이며, 커밋 식별자가 안정적이고 변조를 드러내며 저장소가 어디에 있든 상관없는 이유가 바로 그것입니다. 컨테이너 이미지 다이제스트도 같은 방식이고, 패키지 lock 파일도 마찬가지여서 누군가 다시 게시할 수 있는 버전 번호가 아니라 정확한 바이트에 의존성을 고정합니다.

중복 제거도 같은 발상을 씁니다. 블록마다 해시를 구하는 백업 시스템은 동일한 블록을 한 번만 저장하고, 콘텐츠 전송 네트워크는 다이제스트를 기준으로 캐시하면서도 낡은 데이터를 내보낼 위험이 없습니다. 내용이 다르면 주소도 다르기 때문입니다.

머클 트리는 이를 확장합니다. 해시 쌍을 위로 올려 가며 해시하면 데이터셋 전체를 커밋하는 하나의 루트 다이제스트가 나오고, 덕분에 클라이언트는 전부 내려받지 않고도 어떤 항목 하나가 거기에 속한다는 사실을 검증할 수 있습니다. 인증서 투명성 로그, 블록체인, 그리고 여러 복제 데이터베이스가 모두 이 구조에 기대고 있습니다.

웹훅 서명을 제대로 검증하는 법

패턴은 Stripe, GitHub, Slack을 비롯한 대부분의 서비스에서 똑같습니다. 보내는 쪽이 공유 비밀 키로 원본 요청 본문의 HMAC을 계산해 그 다이제스트를 헤더에 넣고, 받는 쪽이 다시 계산해 비교합니다. 구현이 튼튼한지는 네 가지 세부 사항이 가릅니다.

첫째, 파싱한 JSON을 다시 직렬화한 것이 아니라 원본 본문을 해시해야 합니다. 키 순서와 공백이 바뀌면 바이트가 바뀌고 다이제스트도 바뀝니다. 둘째, 상수 시간으로 비교해야 합니다. 일반적인 문자열 비교는 첫 번째 차이가 어디인지를 흘리고, 요청을 충분히 보내면 그 시간 차이가 곧 서명이 되기 때문입니다. 셋째, 보내는 쪽이 제공하는 타임스탬프를 서명 대상 페이로드에 포함하고 몇 분보다 오래된 것은 거부해야 합니다. 그러지 않으면 가로챈 요청을 언제까지고 재전송할 수 있습니다.

넷째, 비밀 키 두 개를 동시에 지원해야 합니다. 받는 쪽이 하나만 알고 있으면 키 교체가 불가능하며, 보통은 짧은 중첩 기간 동안 둘 중 어느 것이든 받아들이는 방식을 씁니다.

비밀번호 해싱 파라미터 고르기

현재 권장되는 것은 Argon2id이고, 단순한 해시와 달리 파라미터를 받습니다. 메모리, 반복 횟수, 병렬도입니다. 전용 하드웨어를 막아 내는 것은 메모리 비용입니다. GPU와 ASIC은 연산 능력에 비해 코어당 빠른 메모리가 훨씬 적기 때문입니다. 흔히 쓰는 출발점은 메모리 19 MiB에 반복 2회이며, 하드웨어가 허락한다면 더 높입니다.

튜닝은 실측으로 합니다. 실제로 돌아갈 장비에서 측정한 뒤, 로그인 한 번이 대략 0.25초 안에 끝나는 선에서 가장 높은 비용을 고릅니다. 로그인이 몰리면 그 비용이 동시 요청 수만큼 곱해진다는 점도 잊지 마십시오. 작업 계수 12의 bcrypt도 여전히 쓸 만하고 일부 스택에서는 배포하기가 더 쉽습니다. scrypt는 그 중간쯤에 있습니다.

마이그레이션에 누군가의 비밀번호가 필요하지는 않습니다. 다이제스트마다 알고리즘과 파라미터를 함께 저장하고, 검증은 저장된 기록이 말하는 대로 하며, 로그인이 성공하는 바로 그 순간 새 설정으로 다시 해싱하면 됩니다. 몇 달이면 활동 중인 계정 대부분이 알아서 넘어옵니다.

해시가 답이 아닌 경우

식별자를 해싱해 익명화하려는 시도는 통하지 않으며, 그 이유는 외우기보다 이해해 둘 가치가 있습니다. 해시는 결정적이고 입력 공간은 좁습니다. 이메일 주소와 전화번호는 개수가 한정되어 있어서, 다이제스트를 쥔 사람은 자기가 가진 후보를 전부 해싱해 맞춰 볼 수 있습니다. 프라이버시를 지켜 준다고 홍보된 여러 광고·분석 방식이 정확히 이 착각 위에 서 있습니다.

식별자를 드러내지 않으면서 정말로 비교해야 한다면 필요한 도구는 다릅니다. 다른 누구도 갖고 있지 않은 비밀 키를 쓰는 키 기반 해시, 또는 private set intersection을 위해 설계된 프로토콜입니다.

자주 보이는 오용이 두 가지 더 있습니다. 해시는 압축 알고리즘이 아닙니다. 거기서 아무것도 되살릴 수 없기 때문입니다. 그리고 CRC32나 MurmurHash 같은 비암호학적 해시는 해시 테이블과 체크섬에는 훌륭하지만 입력을 적이 고를 수 있는 곳에서는 쓸모가 없습니다. 충돌을 일부러 만들어 내 자료 구조를 선형 탐색으로 떨어뜨릴 수 있기 때문입니다.

자주 묻는 질문

HMAC란 무엇이고 언제 필요한가요?
HMAC는 해시와 비밀 키를 결합해 메시지가 그 키를 가진 쪽에서 왔고 변조되지 않았음을 증명합니다. 일반 해시는 누구나 다시 계산할 수 있어 둘 다 증명하지 못합니다. 웹훅 페이로드와 API 요청 서명이 HMAC를 사용합니다. HMAC 모드로 전환하고 키를 입력하세요.
MD5를 안전하게 사용할 수 있나요?
보안 목적으로는 사용할 수 없습니다. MD5에는 실용적인 충돌 공격이 존재하므로 비밀번호, 서명, 공격자를 상정한 무결성 검증에 써서는 안 됩니다. 다만 체크섬, 캐시 키, ETag처럼 적대적이지 않은 용도로는 여전히 유효하므로 포함했습니다.
그럼 비밀번호는 어떻게 해시해야 하나요?
여기 있는 알고리즘은 쓰지 마세요. 비밀번호 저장에는 bcrypt, scrypt, Argon2처럼 의도적으로 느리고 솔트를 사용하는 전용 알고리즘이 필요합니다. SHA-256 같은 빠른 범용 해시는 초당 수십억 번 무차별 대입이 가능합니다.
입력이 서버로 전송되나요?
아닙니다. SHA 계열은 브라우저의 Web Crypto API를 사용하고 MD5는 페이지 내 JavaScript로 구현되어 있어 텍스트가 기기를 벗어나지 않습니다.
Web Crypto API에 MD5가 없는 이유는 무엇인가요?
암호학적으로 취약하기 때문에 명세에서 의도적으로 제외되었습니다. 그래서 여기서는 별도로 구현했으며, RFC 1321 공식 테스트 벡터로 정확성을 검증했습니다.
한글도 처리되나요?
네. 해시 계산 전에 UTF-8로 인코딩하므로 한국어, 일본어, 중국어, 이모지 모두 표준 명령줄 도구와 동일한 결과가 나옵니다.

마지막 업데이트:

문제 신고

진행 단계, 예상 결과, 실제 결과를 적어 주세요. 비밀 정보와 개인 정보는 삭제해 주세요.

관련 도구