암호학적 해시(SHA-256)와 비밀번호 해싱(bcrypt/Argon2)의 결정적 차이
단방향 암호학적 해시 함수의 원리, 초고속 SHA-256을 비밀번호 저장에 쓰면 안 되는 이유, 레인보우 테이블 공격 방어, 솔트(Salt)와 적응형 KDF(bcrypt, Argon2id)의 실무 적용을 다룹니다.
해시 생성기
서버 전송 없이 100% 브라우저 로컬에서 안전하게 직접 테스트하고 검증해보세요.
단방향 암호학적 해시 함수의 동작 원리와 3대 필수 보안 속성
암호학적 해시 함수는 임의의 가변 길이 데이터를 고정된 길이의 다이제스트(Digest) 문자열로 매핑하는 결정론적 수학 알고리즘입니다. 미국 국립표준기술원(NIST)의 FIPS 180-4 표준으로 정의된 SHA-256을 비롯한 안전한 해시 함수는 다음 3대 성질을 수학적으로 보장해야 합니다:
- 역상 저항성(Pre-image Resistance, 단방향성): 출력값
h가 주어졌을 때,hash(m) = h를 만족하는 원래 입력 메시지m을 역산하는 것이 계산적으로 불가능해야 합니다. - 제2 역상 저항성(Second Pre-image Resistance, 약한 충돌 저항성): 특정 입력
m1이 주어졌을 때, 동일한 해시 결과를 내는 다른 입력m2(hash(m1) = hash(m2))를 찾아내는 것이 불가능해야 합니다. - 충돌 저항성(Collision Resistance, 강한 충돌 저항성): 동일한 해시값을 생성하는 임의의 서로 다른 두 입력쌍
m1과m2를 찾아내는 것이 불가능해야 합니다.
또한 암호학적 해시 함수는 눈사태 효과(Avalanche Effect)를 갖추어, 원본 데이터에서 단 1비트만 달라져도 최종 해시값의 절반 이상의 비트가 무작위로 뒤바뀌어 원본의 패턴을 전혀 유추할 수 없습니다.
빠른 해시 vs 느린 해시: 비밀번호 저장에 SHA-256을 사용하면 안 되는 이유
보안 실무에서 가장 흔히 저지르는 치명적인 실수는 "SHA-256이 암호학적으로 안전하니 비밀번호 저장에도 안전할 것"이라고 오판하는 것입니다. SHA-256, SHA-512, BLAKE3는 초고속 데이터 무결성 검증 해시로 설계되었습니다. 수 기가바이트의 파일 무결성을 검증하고, 초당 수만 건의 TLS 핸드셰이크를 처리하기 위해 CPU 연산 부하를 최소화하도록 최적화되어 있습니다.
하지만 이 "빠른 속도"는 인간이 만든 비밀번호를 보호할 때 치명적인 독이 됩니다. 최신 일반 소비자용 GPU(NVIDIA RTX 4090 등) 한 대는 초당 200억 개 이상의 SHA-256 연산을 병렬로 수행할 수 있습니다. 만약 데이터베이스가 유출되었을 때 비밀번호가 단순 SHA-256으로 해싱되어 있다면, 공격자는 오프라인 무차별 대입 공격(Brute-Force)으로 8자리 영숫자 비밀번호를 몇 시간 만에 전부 뚫어버립니다.
비밀번호 전용 보안 메커니즘: 솔트(Salt), 페퍼(Pepper), 적응형 작업 계수
비밀번호를 안전하게 보관하기 위해서는 반드시 느리고 무거운 키 유도 함수(KDF)를 사용해야 합니다:
- 솔트(Salt): 비밀번호 해싱 시 매번 암호학적 난수로 생성하는 16바이트 이상의 고유 문자열입니다. 해시값과 함께 평문으로 DB에 저장됩니다. 솔트는 미리 계산된 해시 테이블인 레인보우 테이블(Rainbow Table) 공격을 무력화하며, 두 사용자가 동일한 비밀번호를 쓰더라도 완전히 다른 해시값이 저장되도록 보장합니다.
- 페퍼(Pepper): 데이터베이스가 아닌 별도의 환경변수나 KMS(키 관리 서비스)에 보관하는 비밀키입니다. DB가 SQL 인젝션으로 통째로 털리더라도 페퍼가 없으면 해시 해독이 불가능합니다.
- 적응형 작업 계수(Work Factor/Cost): 하드웨어 성능이 발전함에 따라 해시 계산 난이도를 조절할 수 있는 매개변수입니다. 서버가 한 번의 검증에 약 200~500밀리초의 연산 시간이 걸리도록 난이도를 상향 유지하여 GPU 병렬 대입 공격을 무력화합니다.
현대 비밀번호 해싱 표준 비교: bcrypt, PBKDF2, Argon2id
- PBKDF2 (RFC 8018): HMAC을 수십만 번 반복 수행하는 레거시 표준입니다. 검증된 표준이지만 순수 CPU 연산에만 의존하므로 ASIC 전용 하드웨어 채굴기 형태의 병렬 공격에 취약합니다.
- bcrypt: Blowfish 암호 기반으로 지난 20년간 검증된 사실상의 웹 표준입니다. 다만 입력 비밀번호의 길이가 72바이트를 초과하면 자동으로 뒤가 잘리는(Truncation) 한계가 있습니다.
- Argon2id (RFC 9106): 암호학계의 Password Hashing Competition에서 최종 우승한 현존 최고 수준의 알고리즘입니다. 연산 시간뿐 아니라 메모리 사용량(Memory-Hardness)까지 강제하므로, GPU나 ASIC 전용 칩셋으로도 메모리 대역폭 한계 때문에 병렬 공격이 물리적으로 차단됩니다. 신규 프로젝트에는 Argon2id 채택이 가장 권장됩니다.
프로덕션 구현 가이드 및 타이밍 공격(Timing Attack) 방어
비밀번호나 서명 해시를 검증할 때 일반 문자열 비교 연산자(===)를 사용하면, 첫 글자가 틀린 순간 즉시 함수가 리턴되어 미세한 응답 시간 차이가 발생합니다. 공격자는 이 시간 차이를 측정하여 원본 해시값을 한 글자씩 알아내는 타이밍 공격을 수행할 수 있습니다. 따라서 반드시 Node.js의 crypto.timingSafeEqual()과 같은 상수 시간(Constant-time) 비교 함수를 사용해야 합니다.
// Node.js 환경에서의 안전한 해시 생성 및 타이밍 세이프 검증
import crypto from 'node:crypto';
// 데이터 무결성 검증용 빠른 해시 (비밀번호용 아님)
export function computeSha256(data) {
return crypto.createHash('sha256').update(data).digest('hex');
}
// 타이밍 공격을 방어하는 상수 시간 서명 검증
export function verifySignatureSafe(expectedHex, actualHex) {
const a = Buffer.from(expectedHex, 'hex');
const b = Buffer.from(actualHex, 'hex');
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b); // 바이트 일치 여부와 무관하게 일정한 시간에 리턴
}해시 생성기
온라인 무료 해시 생성기. MD5, SHA-1, SHA-256, SHA-512 암호화 해시 즉시 생성.