</>DevTools

#해시 생성기

MD5, SHA-256, SHA-512 해시 생성

해시 함수 고르기: MD5, SHA-256, 그리고 비밀번호에는 무엇을 쓸까

해시 함수는 임의 길이의 입력을 고정 길이 값으로 바꾸는 일방향 함수입니다. 같은 입력은 항상 같은 출력을 내고, 출력에서 입력을 되돌릴 수 없으며, 입력이 1비트만 달라도 출력이 완전히 달라집니다. 다만 '해시를 쓴다'는 말만으로는 안전을 보장하지 못합니다. 용도에 맞는 함수를 고르는 것이 전부입니다.

알고리즘 비교

MD5와 SHA-1이 '깨졌다'는 것은 서로 다른 두 입력이 같은 해시를 갖도록 만들 수 있다는 뜻입니다(충돌). 파일이 위조되지 않았음을 증명하는 용도로는 더 이상 쓸 수 없습니다. 반면 캐시 키 생성이나 데이터 분산처럼 악의적 조작 위험이 없는 곳에서는 MD5가 여전히 빠르고 실용적입니다.

알고리즘출력 길이상태권장 용도
MD5128비트 (32자)충돌 공격 실용화(2004~)체크섬, 캐시 키 등 비보안 용도만
SHA-1160비트 (40자)충돌 공격 실증(2017 SHAttered)신규 설계에 사용 금지
SHA-256256비트 (64자)안전무결성 검증, 서명, 일반 용도의 표준 선택
SHA-512512비트 (128자)안전64비트 환경에서 SHA-256보다 빠를 수 있음
bcrypt / scrypt / Argon2가변안전비밀번호 저장 (아래 참고)

사용 방법

  1. 해시를 만들 텍스트를 입력합니다.
  2. 필요한 알고리즘의 결과를 확인합니다. 같은 입력에 대해 여러 알고리즘 결과를 동시에 비교할 수 있습니다.
  3. 파일 무결성을 확인하려면 배포처가 공개한 값과 문자열을 그대로 비교합니다. 대소문자만 다른 경우가 있으니 소문자로 통일해 비교하세요.

비밀번호에 SHA-256을 쓰면 안 되는 이유

SHA-256의 장점이 비밀번호 저장에서는 그대로 단점이 됩니다. SHA 계열은 의도적으로 매우 빠르게 설계되어 있고, 요즘 GPU는 초당 수십억 번의 SHA-256 연산을 수행합니다. 즉 유출된 해시 목록에 대해 사전 공격과 무차별 대입을 엄청난 속도로 시도할 수 있습니다.

비밀번호에 필요한 것은 '느린 해시'입니다. bcrypt, scrypt, Argon2는 계산 비용(그리고 scrypt·Argon2는 메모리 비용까지)을 파라미터로 조절할 수 있게 설계되어 있어, 공격자의 시도 속도를 의도적으로 떨어뜨립니다. 현재 새로 만드는 시스템에는 Argon2id가 권장되며, bcrypt도 널리 검증된 선택입니다.

솔트도 필수입니다. 솔트는 사용자마다 다른 무작위 값을 비밀번호에 덧붙이는 것으로, 같은 비밀번호가 서로 다른 해시를 갖게 만듭니다. 이것이 레인보우 테이블 공격을 무력화하고, 유출된 DB에서 '같은 해시를 가진 사용자들'을 식별하는 것도 막습니다. bcrypt와 Argon2는 솔트를 자동으로 생성해 결과 문자열에 포함시키므로 별도 관리가 필요 없습니다.

권장 패턴 (Node.js)
import bcrypt from "bcrypt";

// 저장할 때 — cost factor 12 권장 (하드웨어에 맞춰 조정)
const hash = await bcrypt.hash(password, 12);
// $2b$12$Ku0z... 형태로 솔트가 포함되어 있음

// 검증할 때 — 문자열 비교가 아니라 compare 사용
const ok = await bcrypt.compare(password, hash);

해시와 HMAC의 차이

웹훅 서명 검증처럼 '이 데이터가 특정 비밀키를 아는 쪽에서 왔는가'를 확인해야 하는 상황에서는 단순 해시가 아니라 HMAC을 씁니다. SHA-256(secret + data) 같은 직접 연결 방식은 길이 확장 공격에 취약하지만, HMAC은 그 구조적 문제를 피하도록 설계되었습니다. GitHub, Stripe, Slack의 웹훅 서명이 모두 HMAC-SHA256입니다.

덧붙여, 서명 값을 비교할 때는 == 나 === 대신 시간 일정 비교 함수(Node.js의 crypto.timingSafeEqual 등)를 써야 합니다. 일반 문자열 비교는 첫 다른 바이트에서 즉시 반환하므로, 응답 시간 차이를 측정해 올바른 서명을 한 바이트씩 알아내는 공격이 가능합니다.

이런 곳에 씁니다

  • 다운로드한 설치 파일의 SHA-256 체크섬을 배포처 공개값과 비교
  • Git이 객체를 식별하는 방식 확인 (Git은 SHA-1을 쓰지만 충돌 탐지 로직을 추가로 둠)
  • 캐시 키나 ETag 생성 — 내용이 바뀌면 키가 바뀌게
  • 중복 파일 탐지 — 같은 내용인지 빠르게 비교
  • 데이터베이스 샤딩 시 키를 균등하게 분산
  • 개인정보를 직접 저장하지 않고 동일성만 비교해야 할 때 (단, 이메일처럼 후보군이 좁은 값은 해시만으로 보호되지 않음)

자주 묻는 질문

해시를 복호화할 수 있나요?
해시는 암호화가 아니라 일방향 함수이므로 수학적으로 되돌릴 수 없습니다. 인터넷의 '해시 복호화' 서비스는 실제로는 이미 계산해 둔 방대한 (입력, 해시) 목록에서 찾아보는 것입니다. 그래서 흔한 비밀번호는 즉시 찾아지고, 무작위성이 높은 값은 찾지 못합니다. 솔트가 이 방식을 무력화하는 이유이기도 합니다.
MD5는 이제 완전히 쓸모없나요?
보안 목적에는 쓰면 안 되지만, 악의적 위조 가능성이 없는 곳에서는 여전히 유용합니다. 캐시 키 생성, 로컬 파일 변경 감지, 데이터 분산용 버킷 선택 등이 그런 예입니다. 판단 기준은 '누군가 일부러 충돌을 만들면 손해가 발생하는가'입니다. 그렇다면 SHA-256을 쓰세요.
출력 길이가 길수록 더 안전한가요?
출력이 길면 무차별 대입과 충돌 탐색에 필요한 연산량이 커지므로 그 측면에서는 유리합니다. 다만 알고리즘 자체의 구조적 취약점은 길이로 보완되지 않습니다. SHA-1은 160비트지만 안전하지 않고, SHA-256은 256비트로 현재 충분합니다. 그리고 비밀번호 저장에서는 길이가 아니라 계산 속도를 늦추는 것이 핵심입니다.
같은 텍스트인데 해시가 다르게 나옵니다.
거의 항상 입력이 실제로는 다릅니다. 흔한 원인은 끝에 붙은 줄바꿈 문자, 앞뒤 공백, 그리고 줄바꿈 방식 차이(Windows의 CRLF와 Unix의 LF)입니다. 파일 해시라면 텍스트 모드로 열어 줄바꿈이 변환됐을 수도 있습니다. 문자 인코딩이 UTF-8과 EUC-KR로 다른 경우도 바이트가 달라지므로 해시가 달라집니다.
입력값이 서버로 전송되나요?
전송되지 않습니다. 브라우저의 Web Crypto API로 로컬에서 계산합니다. 다만 실제 비밀번호를 여기에 넣어 결과를 저장 용도로 쓰는 것은 애초에 잘못된 접근입니다. 비밀번호는 서버에서 bcrypt나 Argon2로 처리해야 합니다.
해시 값에 대소문자 구분이 있나요?
해시 값 자체는 바이트이고, 이를 16진수 문자열로 표기할 때 대문자든 소문자든 같은 값입니다. 다만 문자열로 비교하는 코드에서는 대소문자가 다르면 불일치로 판정되므로, 비교 전에 양쪽을 소문자로 맞추는 것이 안전합니다.

💡 참고: 체크섬을 비교할 때 눈으로 앞뒤 몇 자만 보는 것은 위험합니다. 전체 문자열을 복사해 붙여넣고 비교하거나, shasum -c 처럼 검증 명령을 쓰세요.

🔗관련 도구🔐 암호화/보안