MiServe DevTools

내 스티커

도구를 여기에 고정하세요. 이 브라우저에 저장됩니다.

bcrypt 해시 생성·검증

원하는 cost로 비밀번호를 bcrypt 해시하고, 비밀번호를 해시와 대조해 검증하고, 해시의 구성 요소를 확인합니다.

비밀번호 해시 생성

cost 10에서는 키 설정을 1,024회 반복합니다. 한 단계 올릴 때마다 작업량이 두 배가 되며, 이는 사용자와 추측하는 공격자 모두에게 해당합니다.

bcrypt 해시

비밀번호 검증

결과

WebAssembly로 브라우저에서 실행됩니다. 붙여 넣은 내용은 업로드되지 않습니다.

이 도구에 대하여

bcrypt가 일부러 느린 이유

비밀번호 데이터베이스는 유출되기 마련이고, 이를 손에 넣은 사람은 하드웨어가 허락하는 한 빠르게 오프라인에서 비밀번호를 추측할 수 있습니다. SHA-256 같은 범용 해시는 빠르게 동작하도록 만들어졌기 때문에 그래픽 카드 한 장으로 초당 수십억 개의 후보를 시도할 수 있습니다. 1999년 Niels Provos와 David Mazières가 발표한 bcrypt는 Blowfish 암호의 비용이 큰 키 설정 과정을 바탕으로, 이를 설정 가능한 횟수만큼 반복해 추측 한 번 한 번을 비싸게 만듭니다.

또한 각 해시에는 16바이트의 무작위 솔트가 들어 있습니다. 같은 비밀번호를 쓰는 두 사용자도 서로 다른 해시를 얻고, 한 솔트에 맞춰 미리 계산해 둔 테이블은 다른 솔트에는 쓸모가 없습니다. bcrypt 해시는 복호화할 수 없습니다. 현실적인 공격은 추측이므로, cost가 얼마든 약한 비밀번호는 금방 뚫립니다.

cost의 의미와 선택 방법

cost는 키 설정 반복 횟수의 밑이 2인 로그입니다. cost 10은 1,024회, cost 12는 4,096회입니다. 1을 올릴 때마다 로그인 한 번과 공격자의 추측 한 번에 드는 시간이 모두 두 배가 됩니다. cost는 해시 안에 기록되므로 나중에 올릴 수 있습니다. 기존 해시는 계속 검증되고, 사용자가 다음에 로그인할 때 새 cost로 비밀번호를 다시 해시하면 됩니다.

서버가 로그인 한 번에 감당할 수 있는 가장 높은 cost를 선택하되, OWASP Password Storage Cheat Sheet가 bcrypt의 최솟값으로 제시하는 10보다 낮추지 마세요. 여기 표시되는 시간은 브라우저의 WebAssembly에서 측정한 것이라 보통 서버의 네이티브 코드보다 느리므로, 실제로 해시를 계산할 머신에서 측정하세요. 이 도구가 cost 14에서 멈추는 이유도 이 때문입니다.

72바이트 제한

bcrypt는 비밀번호의 최대 72바이트까지만 사용합니다. 제한은 문자 수가 아니라 바이트 수입니다. UTF-8에서 é 같은 악센트 문자는 2바이트, 대부분의 CJK 문자는 3바이트, 대부분의 이모지는 4바이트 이상을 차지합니다. 많은 라이브러리가 더 긴 입력을 아무 경고 없이 잘라 내므로, 앞의 72바이트가 같은 두 긴 비밀번호는 같은 해시로 검증됩니다. 여기서 사용하는 Go 구현은 더 긴 입력의 해시를 거부하며, 이 도구는 그런 경우 알려 줍니다.

사용자가 더 긴 비밀번호를 고를 수 있다면, 가장 단순한 해결책은 가입 단계에서 명확한 메시지와 함께 거부하는 것입니다. 흔히 쓰는 우회 방법은 비밀번호를 먼저 SHA-256으로 해시하고, 그 해시 값의 Base64나 hex 텍스트를 bcrypt에 넘기는 것입니다. 해시 값의 원시 바이트를 그대로 넘기면 안 됩니다. 일부 구현은 널 바이트에서 읽기를 멈추기 때문입니다. 또 OWASP 치트 시트는 password shucking이라는 공격의 길을 연다는 이유로 이런 사전 해싱을 권장하지 않습니다. 새 시스템에는 OWASP가 bcrypt보다 Argon2id를 우선 권장하며, Argon2id에는 72바이트 제한이 없습니다.

해시 읽는 법과 이 도구의 실행 방식

bcrypt 해시는 60자입니다. $2b$ 같은 버전 접두사, 두 자리 cost와 $, 솔트 22자, 해시 값 31자로 이루어지며, 솔트와 해시 값은 bcrypt 고유의 Base64 알파벳(./A-Za-z0-9)으로 쓰입니다. 비밀번호 검증에 필요한 모든 것이 이 문자열 하나에 들어 있으므로, 솔트를 저장할 별도의 열이 필요 없습니다.

해시 생성과 검증은 Go의 golang.org/x/crypto/bcrypt 패키지를 WebAssembly로 컴파일해 브라우저의 백그라운드 스레드에서 수행합니다. 비밀번호와 해시는 어디로도 전송되지 않고 저장되지도 않습니다. 이 페이지는 테스트 데이터, 픽스처, 가지고 있는 해시의 확인을 위한 것입니다. 실제 사용자의 비밀번호는 애플리케이션이 서버에서 해시해야 합니다.

자주 묻는 질문

같은 비밀번호인데 왜 매번 다른 해시가 나오나요?

해시마다 새로운 무작위 솔트를 사용하고, 그 솔트가 결과의 일부이기 때문입니다. 비밀번호를 검증할 때 bcrypt는 저장된 해시에서 솔트와 cost를 읽어 같은 계산을 반복합니다. 그래서 다시 해시해서 문자열을 비교하지 말고 항상 검증 함수로 비교해야 합니다.

bcrypt cost는 얼마로 해야 하나요?

최소 10을 사용하고, 서버에서 로그인이 허용할 수 있는 시간 안에 끝난다면 더 높이세요. 한 단계마다 시간이 두 배가 되므로 운영 환경의 하드웨어에서 측정하세요. 하드웨어가 빨라지므로 몇 년마다 값을 다시 검토하세요.

$2a$, $2b$, $2y$는 무엇이 다른가요?

특정 구현의 버그 이후에 나온 개정판을 표시합니다. $2y$는 PHP가 사용하는 crypt_blowfish의 2011년 수정에서, $2b$는 OpenBSD의 2014년 수정에서 나왔습니다. 72바이트 이하의 비밀번호에서는 세 가지 모두 같은 해시 값을 만듭니다. 이 도구는 $2a$로 쓰고 세 가지를 모두 검증합니다.

입력한 비밀번호가 서버로 전송되나요?

아니요. 해시는 사용자의 기기에서 WebAssembly 모듈이 계산하며, 이 도구는 입력한 내용으로 네트워크 요청을 보내지 않습니다. 입력한 내용은 저장되지 않으므로 다음 방문 때 남아 있지 않습니다.

해시의 다른 도구