비밀번호 해싱 원리 완벽 정리 - 평문 저장이 위험한 이유와 솔트, 해시 함수의 작동 방식
많은 서비스가 해킹당해도 사용자 비밀번호가 안전한 이유는 해싱 덕분입니다. 비밀번호 해싱 원리를 이해하면 더 안전한 계정 관리가 가능해집니다. 솔트와 반복 해싱까지 쉽게 정리해드립니다.
![]()
가입한 사이트가 해킹당했다는 뉴스를 보면 가장 먼저 떠오르는 걱정이 비밀번호 유출입니다. 그런데 똑같은 해킹 사고에서도 어떤 회사는 사용자 피해가 거의 없고, 어떤 회사는 즉시 모든 계정이 위험에 빠집니다. 차이는 단 하나, 비밀번호를 어떻게 저장했느냐에 있습니다.
비밀번호 해싱 원리를 알면 왜 어떤 사이트는 비밀번호 분실 시 재발급만 가능하고, 어떤 사이트는 원래 비밀번호를 그대로 알려주는지 이해할 수 있습니다. 그리고 후자가 얼마나 위험한지도 알게 됩니다.
평문 저장이 위험한 이유
평문 저장은 비밀번호를 입력한 그대로 데이터베이스에 기록하는 방식입니다. 사용자가 'qwer1234'를 입력하면 데이터베이스에도 'qwer1234'가 그대로 저장됩니다.
이 방식의 문제는 명확합니다. 데이터베이스가 한 번이라도 유출되면, 공격자는 모든 사용자의 비밀번호를 그대로 손에 넣습니다. 더 큰 문제는 사람들이 여러 사이트에 같은 비밀번호를 돌려쓴다는 점입니다.
- 한 사이트에서 유출된 비밀번호로 다른 사이트 로그인 시도 (크리덴셜 스터핑)
- 이메일과 비밀번호가 함께 유출되면 SNS, 쇼핑몰, 금융 앱까지 연쇄 침해
- 내부 직원 누구나 비밀번호를 열람 가능, 관리자 권한 남용 위험
해시 함수의 기본 개념
해시 함수는 임의 길이의 입력값을 받아 고정된 길이의 출력값으로 변환하는 수학 함수입니다. 같은 입력은 항상 같은 출력을 만들지만, 출력값에서 입력값을 역으로 알아낼 수는 없습니다.
예를 들어 SHA-256 해시 함수에 'hello'를 넣으면 항상 64자리의 동일한 16진수 문자열이 나옵니다. 입력이 한 글자만 바뀌어도 결과는 완전히 달라집니다. 이 특성 때문에 해시 함수는 데이터 무결성 검증, 디지털 서명, 비밀번호 저장 등 다양한 용도로 쓰입니다.
해시 함수의 핵심 특성
- 결정성: 같은 입력은 항상 같은 출력을 생성
- 단방향성: 출력에서 입력을 역산할 수 없음
- 충돌 저항성: 서로 다른 입력이 같은 출력을 만들 확률이 극히 낮음
해시 함수가 어떻게 작동하는지 직접 확인하고 싶다면 해시 생성기로 다양한 문자열을 SHA-256, MD5 등으로 변환해보면 이해가 빠릅니다. 한 글자만 바꿔도 결과가 완전히 달라지는 현상을 눈으로 확인할 수 있습니다.
비밀번호 해싱 원리와 단방향 특성
비밀번호 해싱은 사용자가 입력한 비밀번호를 해시 함수에 통과시킨 결과만 저장하는 방식입니다. 데이터베이스에는 원래 비밀번호가 절대 남지 않습니다.
로그인 검증 과정은 다음과 같이 이루어집니다.
- 사용자가 로그인 화면에서 비밀번호를 입력합니다.
- 서버가 입력값을 같은 해시 함수에 통과시킵니다.
- 저장되어 있던 해시값과 새로 만든 해시값을 비교합니다.
- 일치하면 로그인 성공, 다르면 실패 처리합니다.
해킹으로 데이터베이스가 통째로 유출되어도 공격자가 손에 넣는 것은 해시값일 뿐입니다. 원래 비밀번호를 알아내려면 가능한 모든 문자열을 일일이 해싱해서 대조하는 무차별 대입 공격을 해야 합니다.
바로 이 점이 평문 저장과 결정적으로 다릅니다. 운영자조차 사용자의 원래 비밀번호를 알 수 없기 때문에, 비밀번호를 잊어버렸을 때 '재발급'만 가능하고 '원본 알려주기'는 불가능한 것입니다.
솔트와 레인보우 테이블 방어
해싱만으로는 부족합니다. 레인보우 테이블이라는 공격 기법 때문입니다. 흔한 비밀번호 수십억 개를 미리 해싱해둔 거대한 표를 만들어두고, 유출된 해시값을 표에서 검색하면 원래 비밀번호를 빠르게 찾아낼 수 있습니다.
이를 막기 위한 장치가 솔트(Salt)입니다. 사용자마다 무작위 문자열을 만들어 비밀번호와 함께 해싱하는 방식입니다.
| 구분 | 입력값 | 저장되는 해시 |
|---|---|---|
| 솔트 없음 | qwer1234 | 모든 사용자가 동일 |
| 사용자 A | qwer1234 + 솔트X | 고유한 해시값 |
| 사용자 B | qwer1234 + 솔트Y | 완전히 다른 해시값 |
같은 비밀번호를 쓰는 두 사용자라도 솔트가 다르면 저장되는 해시값이 완전히 달라집니다. 공격자는 사용자별로 따로 공격해야 하므로 시간이 기하급수적으로 늘어나고, 미리 만들어둔 레인보우 테이블도 무력화됩니다.
안전한 비밀번호 해싱 알고리즘 비교
모든 해시 함수가 비밀번호 저장에 적합한 것은 아닙니다. SHA-256, MD5는 매우 빠르게 동작하도록 설계되었기 때문에 오히려 무차별 대입 공격에 취약합니다. 공격자가 초당 수십억 번씩 시도할 수 있기 때문입니다.
| 알고리즘 | 출시 연도 | 비밀번호 저장 적합성 |
|---|---|---|
| MD5 | 1992 | 사용 금지 (충돌 발견) |
| SHA-1 | 1995 | 사용 금지 |
| SHA-256 | 2001 | 일반 무결성용, 비밀번호엔 부적합 |
| bcrypt | 1999 | 현재까지 널리 사용 |
| scrypt | 2009 | 메모리 강도 우수 |
| Argon2 | 2015 | 현재 권장 표준 |
비밀번호 해싱 전용 알고리즘은 일부러 느리게 동작합니다. 정상 로그인은 0.1초가 걸려도 사용자가 체감하기 어렵지만, 공격자가 수십억 번 시도하면 수십 년이 걸리도록 만드는 전략입니다. 게다가 이 알고리즘들은 솔트를 자동으로 생성하고 관리해주기 때문에 개발자가 별도로 구현할 필요가 없습니다.
실무 적용 시 체크포인트
안전한 비밀번호 저장을 위해 직접 서비스를 만들거나 운영하고 있다면 다음을 확인하세요.
- bcrypt, scrypt, Argon2 중 하나를 사용 (직접 SHA-256과 솔트를 조합한 자체 구현은 비권장)
- 솔트는 사용자마다 다르게, 라이브러리가 자동 생성하도록 설정
- 작업 비용(work factor)은 정상 로그인이 0.1~0.5초 걸리는 수준으로 조정
- 비밀번호 분실 시 재발급만 제공 (원본 복원이 가능하다면 그 사이트는 위험 신호)
사용자 입장에서도 할 일이 있습니다. 같은 비밀번호를 여러 사이트에 쓰지 마세요. 한 곳이 뚫리면 다른 곳까지 위험해집니다. 그리고 2단계 인증을 켜두면 비밀번호가 유출되어도 추가 방어선이 생깁니다.
비밀번호 해싱 원리를 이해하면 가입할 서비스를 고르거나 직접 시스템을 만들 때 보안 수준을 판단할 수 있습니다. 지금 사용 중인 사이트의 비밀번호 정책을 한 번 점검하고, 중복 사용 중인 곳이 있다면 분리부터 시작해보세요.