bcrypt 해시 생성기

비밀번호·텍스트를 bcrypt로 해시하고 검증

🔒 모든 계산은 서버로 전송되지 않고 브라우저 안에서만 이루어집니다.

생성


검증

bcrypt 해시 생성기 소개

bcrypt는 비밀번호를 저장하기 위한 해시 함수입니다. MD5나 SHA-256처럼 빠른 해시와 다르게, 계산을 얼마나 느리게 할지 정하는 비용 인자(cost)를 안에 품고 있습니다. 이 도구는 비밀번호를 새 solt로 해시하거나($2b$…), 기존 해시가 어떤 비밀번호와 맞는지 검증합니다.

결과는 $2b$10$… 형태의 60자 문자열입니다. 버전 표시($2b), 비용 인자(10), 22자 base64 salt, 31자 base64 해시가 한 줄에 담겨 있습니다. salt가 해시 문자열 안에 들어 있기 때문에 검증할 때 salt를 따로 보관할 필요가 없습니다. bcrypt는 Web Crypto에 없어 순수 JS로 구현돼 있고, 비용이 큰 계산은 웹 워커에서 돌려 화면이 멈추지 않게 합니다.

비용 인자는 지수다 — 10과 12의 차이

비용 인자 c는 내부 키 세팅을 2^c번 반복하라는 뜻입니다. 그래서 1 늘 때마다 계산 시간이 두 배가 됩니다. 비용 10은 2^10=1,024회, 12는 2^12=4,096회로 4배, 14는 2^14=16,384회로 16배입니다. 이 도구는 4~14 사이만 허용하고 기본값은 10입니다(브라우저 메인 스레드에서 체감 지연 없이 쓸 수 있는 하한이 4입니다).

적절한 비용은 하드웨어에 따라 다릅니다. OWASP는 bcrypt를 쓸 수밖에 없는 레거시 환경이라면 비용 10 이상을 권합니다. 로그인 검증에 서버에서 대략 0.25~0.5초가 걸리도록 맞추는 것이 흔한 기준입니다. 비용을 높이면 유출된 해시를 공격하는 쪽도 그만큼 느려지지만, 정상 로그인도 함께 느려지므로 서버가 감당할 수 있는 선에서 최대한 높입니다.

이미 저장된 해시의 비용을 나중에 올릴 수 있습니다. 사용자가 다음에 로그인할 때 입력한 비밀번호를 더 높은 비용으로 다시 해시해 교체하면 됩니다. bcrypt를 「future-adaptable(미래 적응형)」이라 부른 것이 이 때문입니다(Provos·Mazières, 1999).

72바이트 한계 — 긴 비밀번호와 UTF-8

bcrypt는 비밀번호를 최대 72바이트까지만 반영합니다. 73바이트째부터는 조용히 무시됩니다. 글자 수가 아니라 바이트 수라는 점이 중요합니다. ASCII는 한 글자가 1바이트지만 한글은 UTF-8에서 한 글자가 3바이트라, 한글 비밀번호는 24글자만 넘어도 뒷부분이 잘립니다. 이 도구는 입력이 72바이트를 넘으면 잘린다고 알려 줍니다.

이 한계가 실제 취약점이 된 사례가 있습니다. 2024년 10월 Okta는 AD/LDAP 위임 인증에서 userId+username+password를 이어 붙여 bcrypt로 캐시 키를 만들었는데, username이 52자 이상이면 password 부분이 72바이트 경계 밖으로 밀려 무시됐습니다. 그 결과 특정 조건에서 아무 비밀번호로도 인증이 통과될 수 있었습니다. bcrypt에 넣기 전에 다른 값을 앞에 붙이면 안 된다는 교훈입니다.

긴 비밀번호나 패스프레이즈를 반드시 온전히 반영해야 한다면, bcrypt 앞에 먼저 해시를 거는 방법이 있지만 주의가 필요합니다. OWASP는 사전 해시가 NULL 바이트 문제와 「password shucking」 공격을 부를 수 있어 위험하다고 하고, 꼭 해야 한다면 bcrypt(base64(hmac-sha384(비밀번호, 페퍼)))처럼 감싸라고 안내합니다. 새 시스템이라면 이런 우회 없이 Argon2를 쓰는 편이 낫습니다.

$2a와 $2b, 버전 문자가 붙은 이유

해시 앞의 $2a$, $2b$, $2y$는 알고리즘 버전입니다. $2a는 1999년 원본이고, 2011년 OpenBSD 구현에서 8비트 문자를 다루는 버그가 발견돼 이를 고친 $2b가 나왔습니다. $2y는 PHP 진영에서 같은 버그를 고쳤다는 표시로 쓴 것으로 $2b와 사실상 같습니다. 이 도구는 $2b로 생성하고, 검증할 때는 원본 해시의 버전 문자를 그대로 살려 비교합니다.

그래서 다른 언어(PHP, Node의 bcrypt, 파이썬 passlib 등)에서 만든 해시도 이 도구로 검증할 수 있고, 반대로 이 도구가 만든 해시를 그쪽에서 검증할 수 있습니다. bcrypt 문자열 형식이 표준화돼 있기 때문입니다.

같은 비밀번호인데 매번 다른 해시가 나온다

생성 버튼을 누를 때마다 16바이트 무작위 salt가 새로 만들어지므로, 같은 비밀번호라도 결과 해시가 매번 다릅니다. 이것은 정상이며 오히려 필요한 성질입니다. salt 덕분에 같은 비밀번호를 쓴 두 사용자의 해시가 달라지고, 미리 계산해 둔 표(레인보우 테이블)로 한꺼번에 뚫는 공격이 막힙니다.

검증은 해시 문자열에서 salt와 비용을 꺼내 입력한 비밀번호를 같은 조건으로 다시 해시한 뒤, 타이밍 사이드채널을 줄이는 상수 시간 비교로 일치 여부를 확인합니다. 그래서 원래 해시를 몰라도, 비밀번호와 해시 두 개만 있으면 맞는지 확인할 수 있습니다.

예시

비용을 10에서 12로 올리면

입력
같은 비밀번호를 비용 10과 12로 각각 해시
결과
형식은 같지만 $2b$10$… vs $2b$12$…, 계산 시간은 약 4배

12는 2^12=4,096회로 10의 2^10=1,024회보다 4배입니다. 공격자의 속도도 4배 느려지지만 정상 로그인도 4배 느려지므로 서버 부하를 보며 정합니다.

한글 비밀번호가 잘리는 경우

입력
25자 한글 비밀번호(UTF-8로 75바이트)를 해시
결과
72바이트까지만 반영 — 즉 24자까지만 쓰이고 25번째 글자는 무시됨

한글 한 글자는 UTF-8에서 3바이트라 24×3=72바이트에서 경계에 닿습니다. 도구가 잘림 경고를 표시합니다.

사용 방법

  1. 생성 탭에서 비밀번호를 입력하고 비용(4~14)을 고릅니다.
  2. 생성 버튼을 누르면 새 salt로 $2b$… 해시가 나옵니다.
  3. 검증 탭에서는 비밀번호와 기존 bcrypt 해시를 넣고 일치 여부를 확인합니다.
  4. 결과를 복사해 데이터베이스나 코드에 씁니다.

주요 용어

비용 인자(cost / work factor)
내부 반복을 2^cost회 하라는 지수 값. 1 늘 때마다 계산이 두 배 느려집니다.
salt
해시마다 다른 16바이트 무작위 값. bcrypt는 해시 문자열 안에 salt를 함께 담습니다.
72바이트 한계
bcrypt가 반영하는 비밀번호의 최대 바이트 수. 그 뒤는 무시됩니다.

자주 묻는 질문

같은 비밀번호인데 해시가 매번 달라요.

매번 새 salt를 쓰기 때문이며 정상입니다. 검증은 salt가 해시 안에 들어 있어 문제없이 됩니다.

비용은 몇으로 해야 하나요?

OWASP는 최소 10을 권합니다. 로그인 검증이 서버에서 대략 0.25초 정도 걸리도록 하드웨어에 맞춰 높이세요.

비밀번호가 길면 다 반영되나요?

72바이트까지만 반영됩니다. 한글은 글자당 3바이트라 24자 부근에서 잘립니다.

다른 언어에서 만든 해시도 검증되나요?

됩니다. bcrypt 문자열 형식이 표준이라 PHP·Node·파이썬 등에서 만든 $2a/$2b/$2y 해시를 검증할 수 있습니다.

새 프로젝트에도 bcrypt가 최선인가요?

새로 만든다면 2015년 Password Hashing Competition 우승작이자 2021년 RFC 9106으로 표준화된 Argon2(특히 Argon2id)가 권장됩니다. bcrypt는 이미 쓰던 시스템에 적합합니다.

관련 가이드

출처

기준일:

개인정보와 저장 방식