해시 알고리즘 비교: MD5, SHA, Bcrypt 언제 사용할까?
다양한 해시 알고리즘의 특징과 용도를 비교하고, 각 상황에 맞는 선택 가이드를 제공합니다.

해시 함수란 무엇인가?
해시 함수는 임의의 크기를 가진 데이터를 고정된 크기의 고유한 값으로 변환하는 수학적 함수입니다. 이 변환된 값을 해시(Hash), 다이제스트(Digest), 또는 체크섬(Checksum)이라고 부릅니다. 해시 함수는 현대 컴퓨터 보안의 핵심 구성 요소로, 비밀번호 저장부터 블록체인까지 다양한 분야에서 활용됩니다.
해시 함수를 이해하기 위해 비유를 들어보겠습니다. 해시 함수는 고기를 갈아 햄버거 패티로 만드는 분쇄기와 같습니다. 같은 재료를 넣으면 항상 같은 결과가 나오지만, 패티에서 원래 고기의 형태를 복원하는 것은 불가능합니다. 이것이 바로 해시 함수의 핵심 특성입니다.
해시 함수의 핵심 속성
안전한 암호화 해시 함수는 다음 네 가지 필수 속성을 가져야 합니다.
1. 결정론적 (Deterministic)
같은 입력은 항상 같은 출력을 생성합니다. 이 속성이 없다면 해시는 데이터 검증에 사용될 수 없습니다.
// 항상 동일한 결과
MD5("Hello") === "8b1a9953c4611296a827abf8c47804d7" // true
MD5("Hello") === "8b1a9953c4611296a827abf8c47804d7" // true (언제나)
2. 단방향성 (One-way)
해시값에서 원본 데이터를 역산하는 것은 계산적으로 불가능해야 합니다. 이 속성 덕분에 해시는 비밀번호 저장에 안전하게 사용될 수 있습니다. 데이터베이스가 유출되어도 해시값만으로는 원래 비밀번호를 알 수 없기 때문입니다.
3. 충돌 저항성 (Collision Resistance)
서로 다른 두 입력이 같은 해시값을 생성하는 것을 충돌이라고 합니다. 좋은 해시 함수는 충돌을 찾는 것이 극도로 어려워야 합니다. MD5와 SHA-1이 더 이상 보안 목적으로 권장되지 않는 이유가 바로 충돌이 발견되었기 때문입니다.
4. 눈사태 효과 (Avalanche Effect)
입력이 단 1비트라도 변경되면 출력은 완전히 달라져야 합니다. 이 속성은 유사한 입력에서 해시값의 패턴을 유추하는 것을 방지합니다.
MD5("Hello") = "8b1a9953c4611296a827abf8c47804d7"
MD5("hello") = "5d41402abc4b2a76b9719d911017c592"
// 대문자 하나 차이지만 결과는 완전히 다름
주요 해시 알고리즘 심층 분석
MD5: 왜 더 이상 보안용으로 쓰면 안 될까?
MD5는 1991년 Ronald Rivest가 설계한 128비트 해시 함수입니다. 한때 가장 널리 사용되었지만, 현재는 보안 목적으로 사용해서는 안 됩니다.
입력: "Hello World"
출력: b10a8db164e0754105b7a99be72e3fe5
길이: 128비트 (32자 hex)
MD5의 몰락: 2004년 중국의 Wang Xiaoyun 연구팀이 MD5에서 충돌을 발견했습니다. 이후 2008년에는 가짜 SSL 인증서를 생성하는 데 MD5 충돌이 악용되기도 했습니다. 현재는 일반 컴퓨터로도 수 초 내에 MD5 충돌을 생성할 수 있습니다.
현재 MD5를 사용해도 되는 경우:
- 파일 다운로드 무결성 확인 (보안이 아닌 오류 감지 목적)
- 캐시 키 생성
- 비보안 체크섬
SHA-1: Google의 SHAttered 공격
SHA-1은 NSA가 설계하고 NIST가 표준화한 160비트 해시 함수입니다. MD5보다 안전하다고 여겨졌지만, 2017년 Google과 CWI Amsterdam이 "SHAttered" 공격을 통해 충돌을 시연했습니다.
이 공격에서 연구자들은 동일한 SHA-1 해시값을 가지면서 내용이 다른 두 개의 PDF 파일을 생성했습니다. 공격에 사용된 계산량은 6,500년 상당의 CPU 시간과 110년 상당의 GPU 시간이었습니다. 막대한 자원이 필요했지만, 충돌이 실제로 가능하다는 것이 증명된 순간 SHA-1의 보안 신뢰성은 끝났습니다.
현재 상태: 대부분의 브라우저와 인증 기관은 SHA-1 인증서를 거부합니다.
SHA-256 (SHA-2): 현재의 표준
SHA-2 계열은 SHA-1의 후속으로, SHA-224, SHA-256, SHA-384, SHA-512 등 다양한 변형이 있습니다. 그 중 SHA-256이 가장 널리 사용됩니다.
입력: "Hello World"
출력: a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
길이: 256비트 (64자 hex)
SHA-256과 비트코인: 비트코인은 SHA-256을 핵심으로 사용합니다. 채굴자들은 블록 헤더의 SHA-256 해시값이 특정 조건(앞에 0이 많음)을 만족하는 nonce 값을 찾기 위해 수조 번의 해시 계산을 수행합니다. SHA-256의 예측 불가능성이 이 과정을 공정하게 만듭니다.
용도:
- 디지털 서명 (RSA, ECDSA와 함께)
- SSL/TLS 인증서
- 블록체인
- 파일 무결성 검증
SHA-3: Keccak의 새로운 접근
SHA-3는 2015년 NIST가 표준화한 최신 해시 함수입니다. SHA-2와 완전히 다른 구조(스펀지 구조)를 사용하므로, 만약 SHA-2에서 취약점이 발견되더라도 SHA-3는 영향을 받지 않습니다.
SHA-3의 설계 철학은 "다르게 만들자"였습니다. SHA-2가 Merkle-Damgård 구조를 사용하는 반면, SHA-3의 Keccak 알고리즘은 스펀지 함수를 기반으로 합니다. 이는 일종의 보험입니다. SHA-2가 아직 안전하지만, 미래의 공격에 대비한 대안이 준비되어 있습니다.
Bcrypt: 비밀번호를 위한 특수 해시
Bcrypt는 범용 해시와 달리 의도적으로 느리게 설계되었습니다. 비밀번호 해싱에서 "느림"은 장점입니다. 공격자가 초당 수십억 개의 비밀번호를 시도하는 것을 막아주기 때문입니다.
// 작업 인수(cost factor) 12 사용
bcrypt.hash("password", 12)
// 출력 예시
$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/X4.VVzfQl0Pfy6.nO
Bcrypt 해시값 구조:
$2b$- 알고리즘 버전12$- 작업 인수 (2^12 = 4,096번 반복)- 다음 22자 - Salt (Base64 인코딩)
- 나머지 - 실제 해시값
작업 인수가 1 증가할 때마다 계산 시간이 2배가 됩니다. 현재 권장값은 10-12입니다.
Argon2: 최신 비밀번호 해시
Argon2는 2015년 Password Hashing Competition에서 우승한 알고리즘입니다. 메모리 집약적으로 설계되어 GPU 병렬 공격에 강합니다.
파라미터:
- 메모리: 얼마나 많은 RAM을 사용할지
- 시간: 얼마나 오래 계산할지
- 병렬성: 몇 개의 스레드를 사용할지
Argon2id 변형이 일반 용도로 권장됩니다. 신규 프로젝트에서는 Argon2를 사용하고, 레거시 호환성이 필요하면 Bcrypt를 사용하세요.
실무 활용 가이드
비밀번호 저장: Salt와 Pepper
Salt: 각 비밀번호마다 고유한 랜덤 값을 추가합니다. 같은 비밀번호도 다른 해시값을 생성하므로, 레인보우 테이블 공격을 무력화합니다.
// Salt 사용
password: "password123"
salt: "x7Gh9kL2" (랜덤 생성)
hash: bcrypt("password123" + "x7Gh9kL2")
Pepper: Salt가 데이터베이스에 해시와 함께 저장되는 반면, Pepper는 별도의 비밀로 관리됩니다(환경 변수, 하드웨어 보안 모듈 등). 데이터베이스가 유출되어도 Pepper 없이는 비밀번호를 검증할 수 없습니다.
파일 무결성 검증
소프트웨어 배포 시 SHA-256 체크섬을 함께 제공하면, 다운로드한 파일이 변조되지 않았음을 확인할 수 있습니다.
# 파일 해시 생성
sha256sum ubuntu-22.04.iso
# a1b2c3d4e5f6... ubuntu-22.04.iso
# 검증
echo "a1b2c3d4e5f6... ubuntu-22.04.iso" | sha256sum --check
용도별 알고리즘 선택 가이드
| 용도 | 권장 알고리즘 | 비권장 |
|---|---|---|
| 비밀번호 저장 | Argon2id, Bcrypt, PBKDF2 | MD5, SHA 계열 (너무 빠름) |
| 파일 무결성 | SHA-256, SHA-512 | MD5 (충돌 가능) |
| 디지털 서명 | SHA-256 + RSA/ECDSA | SHA-1 (충돌 공격) |
| API 토큰 | HMAC-SHA256 | - |
| 캐시 키 | MD5, SHA-1 (빠름) | - |
코드 예시
Node.js
const crypto = require('crypto');
const bcrypt = require('bcrypt');
// SHA-256
const sha256 = crypto.createHash('sha256')
.update('Hello World')
.digest('hex');
// Bcrypt
const hash = await bcrypt.hash('password', 12);
const isValid = await bcrypt.compare('password', hash);
Python
import hashlib
import bcrypt
# SHA-256
sha256 = hashlib.sha256(b'Hello World').hexdigest()
# Bcrypt
hashed = bcrypt.hashpw(b'password', bcrypt.gensalt(12))
is_valid = bcrypt.checkpw(b'password', hashed)
Toolypet Hash Tools
Toolypet의 해시 도구로 다양한 해시를 빠르게 생성하고 검증할 수 있습니다:
- MD5/SHA Generator: 텍스트나 파일의 해시값을 즉시 계산
- Bcrypt Tool: 비밀번호 해시 생성 및 검증
- Hash Comparison: 두 해시값을 안전하게 비교 (타이밍 공격 방지)
개발과 테스트에 필요한 해시 작업을 Toolypet에서 간편하게 처리하세요.