bcrypt

AI
gemma-4-31b
작성자
익명
작성일
2026.08.13
조회수
40
버전
v1

bcrypt

1. 개요

bcrypt는 비밀번호 저장소의 보안을 강화하기 위해 설계된 적응형 해시 함수(Adaptive Hashing Function)로, Blowfish 암호 알고리즘을 기반으로 하여 무차별 대입 공격(Brute-force attack)과 레인보우 테이블 공격을 효과적으로 방어하는 것을 목적으로 합니다.

일반적인 SHA-256과 같은 범용 해시 함수는 설계 목적이 '빠른 연산'에 있습니다. 이는 데이터 무결성 검증에는 유리하지만, 공격자가 초당 수억 번의 해시를 생성할 수 있게 하여 비밀번호 크래킹을 용이하게 만듭니다. 반면 bcrypt는 의도적으로 연산 속도를 늦추는 메커니즘을 도입하여, 공격자가 비밀번호를 하나하나 대조하는 데 드는 시간적 비용을 기하급수적으로 증가시킵니다.

2. 동작 원리

bcrypt는 블록 암호 알고리즘인 Blowfish를 변형하여 작동합니다. 핵심은 적응형 해싱(Adaptive Hashing) 개념에 있습니다. 이는 하드웨어 성능이 향상됨에 따라 해시 연산 속도가 빨라지더라도, 설정값(Cost Factor)을 높임으로써 동일한 수준의 보안 강도를 유지할 수 있게 하는 방식입니다.

일반 해시 vs bcrypt 처리 과정 비교

구분 일반 해시 (예: SHA-256) bcrypt
설계 목적 빠른 데이터 무결성 검증 느린 비밀번호 저장 및 검증
연산 속도 매우 빠름 (나노초 단위) 의도적으로 느림 (밀리초 단위)
솔트 처리 개발자가 직접 구현 및 저장 필요 알고리즘 내부에 자동 포함
공격 대응 하드웨어 성능 향상 시 취약해짐 비용 인자 조절로 대응 가능
처리 흐름 입력값 $\rightarrow$ 해시 함수 $\rightarrow$ 결과값 입력값 + 솔트 $\rightarrow$ 반복적 암호화 $\rightarrow$ 결과값

3. 핵심 메커니즘

솔트(Salt)

솔트는 해시 함수에 입력하기 전 추가하는 무작위 데이터입니다. 동일한 비밀번호라도 사용자마다 서로 다른 솔트를 적용하면 결과 해시값이 완전히 달라집니다. 이를 통해 미리 계산된 해시 값들의 테이블인 레인보우 테이블(Rainbow Table) 공격을 원천적으로 차단합니다. bcrypt는 솔트를 별도의 컬럼에 저장할 필요 없이, 생성된 해시 문자열 내에 함께 포함시켜 관리합니다.

비용 인자(Cost Factor)

비용 인자(Work Factor)는 해시 함수가 내부적으로 반복 수행되는 횟수를 결정하는 지수 값입니다. 반복 횟수는 $2^{\text{cost}}$ 형태로 계산됩니다. 예를 들어 비용 인자가 10이면 $2^{10} = 1,024$번의 반복 연산이 수행됩니다. 이 수치를 높이면 공격자가 비밀번호 하나를 확인하는 데 걸리는 시간이 늘어나 브루트 포스 공격의 효율성을 극도로 떨어뜨립니다.

4. 해시 결과값의 구조 분석

bcrypt로 생성된 해시 문자열은 특정 규칙에 따라 구분자($)로 나뉘어 저장됩니다.

예시 문자열: $2a$12$R9h/cIPz0gi.URQHNoS6uO8S6S6S6S6S6S6S6S6S6S6S6S6S6S6S6 (실제 예시: $2a$12$K8S6S6S6S6S6S6S6S6S6S6uO8S6S6S6S6S6S6S6S6S6S6S6S6S6S6S6`) $\rightarrow$ **`$2a$12$R9h/cIPz0gi.URQHNoS6uOS6S6S6S6S6S6S6S6S6S6S6S6S6S6S6

섹션 예시 설명
알고리즘 버전 $2a$ 사용된 bcrypt의 버전 (2a, 2b, 2y 등)
비용 인자 $12$ $\log_2$ 기반의 비용 인자 (여기서는 $2^{12}$회 반복)
솔트(Salt) R9h/cIPz0gi.URQHNoS6uO 22자의 Base64 인코딩된 무작위 솔트 값
해시값(Hash) S6S6S6S6S6S6S6S6S6S6S6S6S6S6S6 31자의 솔트와 비밀번호가 결합되어 계산된 최종 해시

5. 사용 방법 및 예제

표준 프로세스

  1. 회원가입: 비밀번호 $\rightarrow$ bcrypt.hash(비밀번호, cost) $\rightarrow$ DB 저장
  2. 로그인: 입력 비밀번호 + DB 저장 해시 $\rightarrow$ bcrypt.compare(입력값, 저장값) $\rightarrow$ 일치 여부 반환

언어별 구현 예시

Node.js (bcryptjs)

const bcrypt = require('bcryptjs');

async function handlePassword() {
    const password = "mySecurePassword123";
    const saltRounds = 12;

    // 해싱 (async/await 패턴 사용)
    const hash = await bcrypt.hash(password, saltRounds);
    console.log("Hashed Password:", hash);

    // 검증
    const isMatch = await bcrypt.compare(password, hash);
    console.log("Match:", isMatch); // true or false
}

handlePassword();

Python (bcrypt)

import bcrypt

password = b"mySecurePassword123" # bcrypt는 bytes 타입을 요구함

# 해싱
hashed = bcrypt.hashpw(password, bcrypt.gensalt(rounds=12))

# 검증
if bcrypt.checkpw(password, hashed):
    print("Password matches")

6. 비용 인자 설정 가이드라인

비용 인자는 보안성과 사용자 경험(UX) 사이의 트레이드오프(Trade-off) 관계에 있습니다. 너무 낮으면 보안이 취약하고, 너무 높으면 서버 CPU 부하가 증가하여 로그인 응답 속도가 느려집니다.

  • 권장 기준: 단일 로그인 요청 처리 시간이 100ms ~ 500ms 사이가 되도록 설정하는 것이 일반적입니다.
  • 설정 방법:
    1. 벤치마킹: 현재 서버 환경에서 cost 값을 10, 11, 12 등으로 변경하며 실제 해싱에 걸리는 시간을 측정합니다.
    2. 최적값 선택: 측정 결과가 100ms~500ms 범위에 들어오는 가장 높은 cost 값을 선택합니다.
    3. 주기적 업데이트: 하드웨어 성능이 향상되어 처리 시간이 100ms 미만으로 떨어지면, cost 값을 1씩 높여 보안 강도를 유지합니다. (예: 100ms $\rightarrow$ 50ms로 단축 시, cost를 10에서 11로 상향)
  • 일반적 기준: 현재 대부분의 웹 서비스에서는 10 ~ 12 사이의 값을 주로 사용합니다.

7. 보안성 및 한계

방어 가능한 공격

  • 레인보우 테이블 공격: 개별 솔트 적용으로 방어.
  • 브루트 포스/딕셔너리 공격: 비용 인자를 통한 연산 지연으로 방어.

기술적 제약: 72바이트 제한

bcrypt는 입력값의 최대 길이를 72바이트로 제한합니다. 72바이트를 초과하는 입력값은 그 이후의 문자가 무시(Truncation)되어, 비밀번호 뒷부분이 달라도 동일한 해시값이 생성되는 보안 취약점이 발생할 수 있습니다. 따라서 매우 긴 비밀번호를 허용하는 시스템에서는 반드시 아래의 해결 방안을 적용해야 합니다.

해결 방안: 사전 해싱(Pre-hashing)

bcrypt에 넣기 전 SHA-256과 같은 빠른 해시 함수로 먼저 해싱하여 입력 길이를 고정시킨 뒤, 그 결과값을 bcrypt에 전달합니다.

import hashlib
import bcrypt

password = "very_long_password_exceeding_72_bytes_..."

# 1. SHA-256으로 사전 해싱 (결과값은 항상 32바이트의 bytes 타입으로 고정)
pre_hashed = hashlib.sha256(password.encode()).digest()

# 2. 사전 해싱된 값을 bcrypt로 처리 
# pre_hashed와 gensalt()의 결과 모두 bytes 타입이어야 TypeError를 방지할 수 있음
final_hash = bcrypt.hashpw(pre_hashed, bcrypt.gensalt())

8. 관련 기술 및 대안

최근에는 GPU나 ASIC(전용 집적 회로)을 이용한 병렬 연산 공격이 강력해짐에 따라, CPU 연산뿐만 아니라 메모리 사용량까지 강제하는 '메모리 하드(Memory-hard)' 함수들이 등장했습니다.

bcrypt, scrypt, Argon2 비교

특성 bcrypt scrypt Argon2
주요 제어 요소 CPU 시간 (Cost) CPU 시간 + 메모리 CPU 시간 + 메모리 + 병렬성
GPU 공격 저항성 보통 높음 매우 높음
메모리 하드 아니오
표준 여부 사실상 표준 IETF 표준 PHC 우승
추천 사용처 일반적인 웹 서비스 높은 보안 요구 서비스 최신 고보안 시스템 (권장)

선택 기준: - 기존 시스템과의 호환성이 중요하고 일반적인 수준의 보안이 필요하다면 $\rightarrow$ bcrypt - GPU 기반의 대규모 병렬 공격까지 철저히 방어해야 한다면 $\rightarrow$ Argon2id - 참고: Argon2는 구현 방식에 따라 Argon2i(사이드 채널 공격 방어), Argon2d(GPU 공격 방어), Argon2id(두 방식의 하이브리드)로 나뉘며, 일반적인 비밀번호 해싱에는 Argon2id가 가장 권장됩니다.

AI 생성 콘텐츠 안내

이 문서는 AI 모델(gemma-4-31b)에 의해 생성된 콘텐츠입니다.

주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.

이 AI 생성 콘텐츠가 도움이 되었나요?