"비밀번호를 데이터베이스에 있는 그대로 저장하지 마라" — 그럼 어떻게 저장할까요? 답은 해싱입니다. 동작 원리와 안전하게 하기 위한 핵심을 설명합니다(공격 절차 없음).
해싱 ≠ 암호화
이 둘은 헷갈리기 쉽지만 목표가 정반대입니다. **암호화는 "키로 되돌릴 수 있어, 나중에 다시 읽을 수 있다"**이고, **해싱은 "단방향 — 되돌릴 수 없다"**입니다. 비밀번호는 운영자조차 다시 읽을 필요가 없는 정보이므로, 의도적으로 되돌릴 수 없는 해시가 알맞습니다.
암호화 (가역)
평문 ⇄ 암호문. 키가 되돌림. 다시 읽을 데이터에 사용
해싱 (단방향)
비밀번호 → 해시. 되돌릴 수 없음. 비밀번호 저장에 사용
로그인 시에는 "입력된 비밀번호를 같은 방식으로 해싱해 저장된 해시와 일치하는지 확인"합니다. 원본을 복원할 필요는 전혀 없습니다.
왜 "날것의 MD5/SHA-256"으로는 부족한가
MD5 와 SHA-256 은 빠른 해시입니다. 다른 용도에서는 유용한 성질이지만, 비밀번호 저장에는 약점입니다. 공격자가 유출된 해시에 대해 초당 엄청난 수의 추측을 계산할 수 있기 때문입니다.
- 레인보우 테이블: "흔한 비밀번호 → 그 해시"를 거대하게 미리 계산한 테이블. 날것의 해시라면 조회만으로 일치를 찾아냅니다.
- 무차별 대입: 해시가 빠를수록 단위 시간당 추측이 많아져 — 즉 깨기 쉬워집니다.
두 가지 해법
솔트 추가 (사용자마다 다른 값)
해싱하기 전에 사용자마다 다른 무작위 값(솔트)을 섞으세요. 그러면 같은 비밀번호도 사람마다 다르게 저장되어 레인보우 테이블을 무력화하고, 한 번의 크래킹으로 여러 계정에 걸친 재사용 비밀번호까지 깨는 것을 막습니다.
의도적으로 느린 전용 해시 사용
bcrypt / Argon2 / scrypt 는 계산을 의도적으로 비싸게(비용 파라미터) 만들 수 있습니다. 정당한 로그인 한 번에서는 아무도 못 느낄 정도의 느림이, 공격자의 무차별 대입을 비현실적인 속도로 떨어뜨립니다. 솔트도 이들에 내장되어 있습니다.
본 사이트의 견해: 직접 만들지 마라
"MD5에 솔트만 더하면 충분하지 않나?" — 이것이 전형적인 함정입니다. 안전한 비밀번호 저장은 솔트의 생성과 저장, 비용 조정, 타이밍 차이 처리에도 달려 있습니다. 그것을 직접 조립하기보다는 언어/프레임워크의 공식 비밀번호 함수에 기대세요(대부분 내부적으로 bcrypt/Argon2를 사용합니다). 새 시스템에는 Argon2id 를 첫 번째 선택으로 삼으세요.
다음으로 읽기
- 용어집: 솔트란 (재사용 공격을 무력화하는 사용자별 "양념")
- 학습: 비밀번호를 안전하게 저장하는 법 (실전 해싱 + 솔트)
- 기초: 비밀번호를 올바르게 저장하기 (평문 금지) / 비밀번호 관리자 고르기
FAQ
Q해싱은 암호화와 무엇이 다른가요?
암호화는 가역적입니다. 키가 있으면 데이터를 다시 복호화할 수 있는데, 이는 다시 읽을 데이터에 필요한 성질입니다. 해싱은 단방향이라 되돌릴 수 없습니다. 비밀번호는 운영자조차 다시 읽어낼 필요가 사실 없으므로, 의도적으로 되돌릴 수 없는 해시가 잘 맞습니다. 데이터베이스가 탈취되어도 해시에서 원래 비밀번호를 곧바로 끄집어낼 수 없습니다.
QMD5나 SHA-256으로 해싱하면 충분히 안전한가요?
아닙니다, 그것만으로는 안 됩니다. MD5/SHA-256은 '빠른' 해시이므로, 공격자가 초당 엄청난 수의 추측을 시도할 수 있고, 흔한 비밀번호는 무차별 대입이나 레인보우 테이블(미리 계산된 조회 테이블)에 무너집니다. 안전하게 하려면 사용자별 '솔트'를 추가하고 의도적으로 느린 전용 해시(bcrypt, Argon2, scrypt)를 사용하세요.
Q실제로 무엇을 써야 하나요?
새 시스템에는 Argon2(특히 Argon2id)가 첫 번째 선택이고, bcrypt나 scrypt가 견실한 대안입니다. 이들 모두 솔트와 조정 가능한 비용 계수를 설계에 내장하고 있습니다. MD5+솔트를 직접 엮기보다는, 이 표준 구현(언어/프레임워크의 공식 함수)을 사용하는 것이 더 안전하고 믿을 만합니다.