비밀번호 엔트로피: 측정 방법과 강도 극대화
‘강력한 비밀번호’는 대문자, 숫자, 특수 문자를 모두 포함해야 한다는 얘기를 한 번쯤 들어 봤을 겁니다. 그런데 P@$$w0rd!는 이 규칙을 모두 충족하면서도 1초 안에 해독됩니다.
비밀번호 강도의 진짜 척도는 어떤 문자를 쓰는가가 아니라 엔트로피입니다. 엔트로피는 정보 이론의 개념으로, 비밀번호가 실제로 얼마나 예측 불가능한지를 정량화합니다.
아래에서 비밀번호 엔트로피가 작동하는 원리, 계산 방법, 실제로 해독하기 어려운 비밀번호를 만드는 방법을 살펴봅니다.
비밀번호 엔트로피란?
비밀번호 엔트로피는 비밀번호의 예측 불가능성을 비트 단위로 측정합니다. 엔트로피가 1비트 늘어날 때마다 공격자가 무차별 대입으로 시도해야 하는 횟수가 두 배가 됩니다.
주사위에 비유할 수 있습니다. 6면 주사위는 한 번 굴릴 때마다 약 2.6비트의 엔트로피가 있습니다. 결과가 6가지뿐이기 때문입니다. 20면 주사위는 약 4.3비트입니다. 면이 많을수록 불확실성이 커집니다.
비밀번호도 같습니다. 가능한 문자가 많을수록(‘큰 주사위’) 그리고 문자 수가 많을수록(‘많이 굴릴수록’) 엔트로피가 커집니다.
엔트로피가 복잡성 규칙보다 좋은 척도인 이유가 여기 있습니다. 비밀번호가 복잡해 보여도(Tr0ub4dor&3) 예측 가능한 패턴을 따르면 엔트로피는 낮습니다. 반대로 단순해 보이는 패스프레이즈(correct horse battery staple)는 큰 후보 집합에서 뽑혔다면 엔트로피가 높을 수 있습니다.
공식: 비밀번호 엔트로피 계산법
공식은 간단합니다.
E = L × log₂(R)
각 기호의 의미는 다음과 같습니다.
- E = 엔트로피(비트)
- L = 비밀번호 길이(문자 수)
- R = 집합 크기(한 자리에 올 수 있는 문자 수)
문자 집합 크기
| 문자 종류 | 집합 크기 (R) | 문자당 비트 |
|---|---|---|
| 소문자만 (a-z) | 26 | 4.70 |
| 소문자 + 숫자 | 36 | 5.17 |
| 대소문자 + 숫자 | 62 | 5.95 |
| 출력 가능한 전체 ASCII | 94 | 6.55 |
| Diceware 단어 목록 | 7,776 | 단어당 12.92 |
코드로 계산하기
// JavaScript로 비밀번호 엔트로피 계산
const entropy = (length, poolSize) =>
length * Math.log2(poolSize);
entropy(8, 26); // → 37.60 비트 (소문자만)
entropy(12, 62); // → 71.45 비트 (영숫자)
entropy(16, 94); // → 104.87 비트 (전체 문자 집합)
import math
def entropy(length: int, pool_size: int) -> float:
return length * math.log2(pool_size)
entropy(8, 26) # → 37.60 비트
entropy(12, 62) # → 71.45 비트
entropy(16, 94) # → 104.87 비트
중요: 이 공식은 각 문자가 균일한 무작위로 선택됐다고 가정합니다. 사람이 패턴이나 사전 단어를 바탕으로 고른 비밀번호라면 실제 엔트로피는 이론치보다 훨씬 낮습니다.
엔트로피는 얼마나 있어야 충분한가?
답은 무엇을 보호하는지, 공격자가 얼마나 빠르게 시도할 수 있는지에 달려 있습니다.
요즘 GPU는 MD5 같은 빠른 알고리즘에 대해 초당 10¹²(1조) 회 이상의 비밀번호 해시를 시험할 수 있습니다. 실제 기준으로 옮기면 이렇습니다.
| 엔트로피(비트) | 강도 | 10¹² 회/초에서의 해독 시간 | 권장 용도 |
|---|---|---|---|
| < 40 | 약함 | 1초 미만 | 사용 금지 |
| 40–59 | 보통 | 수 초 ~ 수 시간 | 일회성 계정 |
| 60–79 | 강함 | 수 일 ~ 수 세기 | 일반 계정 |
| 80–99 | 매우 강함 | 수천 년 이상 | 이메일, 금융 |
| 100+ | 극강 | 우주 열 죽음을 넘어서는 시간 | 암호화 키, 마스터 비밀번호 |
출력 가능한 전체 ASCII 집합을 쓰는 16자 비밀번호는 약 105비트의 엔트로피로 ‘극강’ 구간에 듭니다. 무작위 비밀번호 생성기에서 바로 생성할 수 있고, 모든 결과에 실시간 엔트로피 분석이 표시됩니다.
NIST 권고 (2024년 개정)
2024년 개정 NIST SP 800-63B는 비밀번호 지침에 큰 변화를 가져왔습니다.
- 필수 복잡성 규칙 폐지(특수 문자 강제 요구 철회)
- 주기적 비밀번호 변경 의무 폐지
- 최소 길이 15자로 상향(이전 8자에서 상향)
- 유출된 비밀번호 데이터베이스 대조 강조
- 복잡성보다 길이와 무작위성을 우선
이 변화는 엔트로피 수학이 오래전부터 보여 준 결론을 반영합니다. 길이와 무작위성이 문자 종류의 다양성보다 중요합니다.
왜 길이가 복잡성을 이기는가
수학으로 확인해 봅니다. 12자 비밀번호의 엔트로피를 높이는 두 가지 방법을 비교해 봅시다.
옵션 A — 12자를 유지하고 영숫자(62)에서 전체 ASCII(94)로 전환:
- 12 × log₂(94) − 12 × log₂(62) = 78.66 − 71.45 = +7.21 비트
옵션 B — 영숫자(62)를 유지하고 한 글자를 추가(12 → 13):
- 13 × log₂(62) − 12 × log₂(62) = 77.40 − 71.45 = +5.95 비트
한 글자만 추가해도 더 큰 문자 집합으로 바꾼 것과 비슷한 엔트로피 증가를 얻고, 두 글자를 추가하면 그 증가분을 넘어섭니다.
이제 P@$$w0rd!(9자)를 봅시다. 전체 ASCII 집합을 쓰지만 길이가 짧고, 사전 공격이 이미 파악한 ‘leet speak’ 패턴을 따릅니다. 따라서 유효 엔트로피는 이론치 59비트보다 훨씬 낮습니다.
결론: 진짜 무작위 비밀번호라면 문자 종류를 늘리는 것보다 길이를 늘리는 쪽이 더 효율적입니다. 다만 진짜 적은 길이 부족이 아니라 예측 가능성입니다.
패스프레이즈 vs 무작위 비밀번호
| 항목 | 무작위 비밀번호 | 패스프레이즈 (Diceware) |
|---|---|---|
| 예시 | kX#9mP$2vL!nQ7wR | correct horse battery staple |
| 단위당 비트 | 문자당 6.55 | 단어당 12.92 |
| 약 78비트에 필요한 길이 | 12자 | 6단어 |
| 암기 용이성 | 낮음 | 높음 |
| 모바일 입력 | 번거로움 | 쉬움 |
| 적합한 용도 | 비밀번호 관리자 저장용 | 마스터 비밀번호, 암기 로그인 |
Diceware 작동 방식
Diceware는 7,776개(6⁵ = 7,776) 항목의 단어 목록을 씁니다. 주사위 다섯 개를 굴려 단어를 하나 고르고, 이렇게 뽑은 단어는 정확히 단어당 12.92비트의 엔트로피를 갖습니다.
4단어는 약 51비트, 6단어는 약 77비트입니다.
어느 쪽을 써야 할까?
- 관리자에 저장할 비밀번호: 전체 문자 집합을 쓰는 16자 이상 무작위 비밀번호를 쓰세요. 직접 입력할 일이 없으므로 암기 용이성은 중요하지 않습니다. 무작위 비밀번호 생성기는 한 번에 최대 50개를 일괄 생성합니다.
- 마스터 비밀번호: 5
6단어 Diceware 패스프레이즈를 쓰세요. 6477비트 엔트로피를 확보하면서 매일 타이핑할 수 있습니다. - API 키와 토큰: 사람이 기억할 필요가 없으므로 엔트로피를 최대화하려면
openssl rand나crypto.randomBytes()를 쓰세요.
실무에서의 엔트로피: 개발자 도구와 코드
개발자들이 고엔트로피 비밀값을 만들 때 자주 쓰는 방법입니다.
브라우저 (Web Crypto API)
// 암호학적으로 안전한 비밀번호 생성
function generatePassword(length, charset) {
const array = new Uint32Array(length);
crypto.getRandomValues(array);
return Array.from(array, v => charset[v % charset.length]).join('');
}
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';
generatePassword(16, chars);
// → 'kX#9mP$2vL!nQ7wR' (매번 무작위)
Node.js
const crypto = require('crypto');
const token = crypto.randomBytes(32).toString('base64url');
// → 'Ql2Hj8xK9mNp3rVw5tYz7uBa0cEf4gIk' (43자, 256비트)
Python
import secrets
token = secrets.token_urlsafe(32) # 256비트 엔트로피
password = secrets.token_hex(16) # 128비트, 16진수 형식
명령줄
# 192비트 엔트로피, Base64 인코딩
openssl rand -base64 24
# 256비트, 16진수 인코딩
openssl rand -hex 32
방식별 엔트로피 비교
| 방식 | 출력 길이 | 엔트로피(비트) |
|---|---|---|
| UUID v4 | 36자 | 122 |
openssl rand -base64 24 | 32자 | 192 |
| 전체 ASCII 16자 | 16자 | 105 |
| 6단어 Diceware | 약 30자 | 78 |
| 4단어 Diceware | 약 20자 | 52 |
Math.random()은 보안 용도에 쓰지 마세요. 비암호학적 PRNG를 쓰므로 시드를 알면 출력이 예측 가능합니다. 브라우저에서는crypto.getRandomValues(), Node.js에서는crypto.randomBytes()를 쓰세요.
비밀번호 저장: 엔트로피만으로는 부족한 이유
128비트 비밀번호라도 서버가 평문 MD5 해시로 저장하면 소용이 없습니다. 데이터베이스가 유출되면 공격자는 GPU 한 대로 초당 수조 회의 MD5 해시를 시험할 수 있습니다.
느린 해싱 알고리즘이 여기서 등장합니다. 의도적으로 한 번의 추측을 비싸게 만듭니다.
| 알고리즘 | GPU 속도 | 실효 감속 |
|---|---|---|
| MD5 | 초당 약 100억 회 | 기준선 (사용 금지) |
| SHA-256 | 초당 약 50억 회 | 약 2배 느림 |
| bcrypt (cost=12) | 초당 약 5회 | 약 20억 배 느림 |
| argon2id | 초당 약 2회 | 약 50억 배 느림 |
bcrypt의 cost 파라미터가 영리한 이유입니다. 값이 1 늘어날 때마다 필요한 계산량이 두 배가 됩니다. cost 12는 2¹² = 4,096회의 해싱 라운드입니다. 결과적으로 비밀번호 엔트로피 위에 12비트의 ‘저장 엔트로피’를 얹는 효과가 있습니다.
이중 방어: 고엔트로피 비밀번호는 오프라인 무차별 대입을 막고, 느린 해싱은 데이터베이스 유출에 대응합니다. 둘 다 필요합니다.
해시 알고리즘은 MD5 vs SHA-256 비교에서, 알고리즘별 출력 차이는 MD5 해시 생성기에서 확인할 수 있습니다.
자주 듣는 비밀번호 오해 바로잡기
’90일마다 비밀번호를 변경하세요’
NIST의 2024년 지침은 주기적 변경 의무화를 명시적으로 권장하지 않습니다. 잦은 변경을 강요하면 사용자는 더 약하고 예측 가능한 비밀번호를 고릅니다. 끝에 숫자를 하나 붙이거나 몇 개를 돌려 쓰는 식입니다. 유출이 의심될 때만 비밀번호를 바꾸세요.
‘a→@, e→3 치환이 더 강하게 만든다’
Leet speak 치환은 사전 공격이 가장 먼저 시도하는 패턴입니다. password의 a를 @로 바꿔도 공격자가 이미 예상하므로 추가 엔트로피는 사실상 0에 가깝습니다.
엔트로피를 높이는 건 기발한 치환이 아니라 진짜 무작위성입니다.
‘기호를 넣은 8자면 충분하다’
94자짜리 전체 ASCII 집합을 써도 8자는 52비트 엔트로피에 불과합니다. 초당 10¹² 회의 속도라면 약 75분 만에 해독됩니다.
최소 12자, 중요한 계정이라면 16자 이상을 쓰세요.
‘복잡해 보일수록 안전하다’
시각적 복잡성과 엔트로피는 다릅니다. Tr0ub4dor&3은 복잡해 보이지만 ‘기본 단어 + 치환’ 패턴을 따릅니다. mfYq8kL2nR은 단순해 보여도 진짜 무작위여서 엔트로피가 더 높습니다.
인증, 세션 관리, 유출 모니터링을 포함한 실전 체크리스트는 웹 보안 모범 사례 가이드에서 확인할 수 있습니다.
FAQ
보안에 충분한 엔트로피 비트는 몇 비트인가요?
대부분의 온라인 계정에는 60~80비트면 충분히 강합니다. 마스터 비밀번호나 암호화 키처럼 고가치 대상이면 100비트 이상을 목표로 하세요. 1비트 늘어날 때마다 공격자의 비용이 두 배가 됩니다.
특수 문자를 넣으면 항상 엔트로피가 올라가나요?
아닙니다. 해당 문자가 전체 집합에서 무작위로 선택됐을 때만 엔트로피가 올라갑니다. a를 @로 바꾸거나 끝에 !를 붙이는 식의 예측 가능한 치환은 공격자의 사전에 이미 반영돼 있어 엔트로피를 거의 더하지 못합니다.
4단어 Diceware 패스프레이즈의 엔트로피는 얼마인가요?
표준 7,776단어 Diceware 목록을 쓰면 단어 하나가 12.92비트를 기여합니다. 4단어면 약 51.7비트로 낮은 보안 등급에 적합합니다. 중요한 계정에는 56단어(6478비트)를 쓰세요.
Math.random()을 비밀번호 생성에 써도 되나요?
아닙니다. Math.random()은 암호학적으로 안전하지 않은 의사 난수 생성기입니다. 보안이 중요한 난수 생성에는 브라우저에서 crypto.getRandomValues(), Node.js에서 crypto.randomBytes()를 쓰세요.
bcrypt의 cost 파라미터는 보안에 어떤 영향을 주나요?
bcrypt의 cost가 1 늘어날 때마다 해싱(따라서 무차별 대입)에 필요한 계산량이 두 배가 됩니다. cost 12는 2¹² = 4,096회 반복이며, 비밀번호 엔트로피 위에 사실상 12비트의 난이도를 더합니다.
NIST의 2024년 비밀번호 지침에서 무엇이 바뀌었나요?
NIST SP 800-63B는 필수 복잡성 요구(특수 문자 강제, 대소문자 혼용)와 주기적 교체를 폐지했습니다. 새 지침은 더 긴 비밀번호(15자 이상 권장), 유출 비밀번호 데이터베이스 대조, 공백을 포함한 모든 출력 가능 문자 허용을 중시합니다.
핵심 요약
- 엔트로피 = L × log₂(R) — 1비트 늘어날 때마다 추측 횟수가 두 배가 됩니다.
- 길이 > 복잡성 — 문자 집합을 넓히는 것보다 한 글자를 추가하는 쪽이 효과적입니다.
- 암호학적 API를 쓰세요 —
crypto.getRandomValues()또는crypto.randomBytes().Math.random()은 쓰지 마세요. - 비밀번호 관리자 + 무작위 생성 조합이 대부분의 사용자에게 최선입니다.
- 서버 측도 중요합니다 — bcrypt나 argon2를 쓰고 MD5로는 저장하지 마세요.
고엔트로피 비밀번호가 필요하면 무작위 비밀번호 생성기에서 바로 만들 수 있습니다. 생성되는 모든 비밀번호에 실시간 엔트로피 분석이 표시됩니다.