사용자 비밀번호 암호화를 위한 키 스트레칭 및 솔팅 알고리즘의 원리

단순한 해시 함수로 표시된 낡고 금간 방패가 금고를 보호하고 있지만, 현대적인 해킹 도구들이 그 방어를 뚫고 침입하는 모습을 담은 이미지입니다.

암호화의 기초: 왜 단순한 해시는 더 이상 안전하지 않은가

사용자 비밀번호를 데이터베이스에 평문으로 저장하는 것은 현대 보안 기준에서 치명적인 과실입니다, 과거에는 md5나 sha-1과 같은 암호화 해시 함수를 사용하여 비밀번호를 변환해 저장하는 것이 일반적이었습니다. 한편 이러한 방식은 두 가지 근본적인 취약점을 가지고 있습니다. 첫째, 레인보우 테이블 공격에 극도로 취약합니다. 공격자는 미리 계산된 해시 값 사전을 구축하여 유출된 해시 값을 빠르게 역조회할 수 있습니다. 둘째, 현대의 고성능 GPU와 ASIC 하드웨어를 이용하면 초당 수십억 건의 해시를 계산할 수 있어, 짧고 일반적인 비밀번호는 순식간에 크랙될 수 있습니다. 이에 따라 단순 해시는 더 이상 비밀번호 보호의 최소 요구사항에도 미치지 못합니다. 이 문제를 해결하기 위해 키 스트레칭과 솔팅이 필수적인 보안 레이어로 자리 잡았습니다.

솔팅(Salting)의 전략적 방어 메커니즘

솔팅은 레인보우 테이블 공격을 무력화하기 위한 핵심 전략입니다. 이는 비밀번호에 임의의 데이터(솔트)를 추가한 후 해시화하는 과정을 의미합니다. 솔트는 각 사용자마다 고유하게 생성되며, 일반적으로 해시된 비밀번호와 함께 데이터베이스에 평문으로 저장됩니다.

솔팅의 작동 원리와 보안적 이점

솔팅이 제공하는 보안성 향상은 주로 두 가지 측면에서 평가됩니다. 첫째, 동일한 비밀번호를 가진 사용자들이라도 서로 다른 솔트를 부여받으면 전혀 다른 해시 값을 생성하게 됩니다. 이는 공격자가 하나의 해시를 크랙했다 하더라도 다른 사용자의 동일 비밀번호 해시를 알아낼 수 없게 만듭니다. 둘째, 가장 결정적인 것은 레인보우 테이블의 실용성을 박탈한다는 점입니다. 공격자가 미리 계산해 놓은 사전은 특정 비밀번호와 특정 솔트의 조합에 대해서만 유효합니다. 수십억 개의 가능한 솔트 각각에 대해 새로운 레인보우 테이블을 생성해야 한다는 것은 현실적으로 불가능한 계산 비용을 요구합니다. 솔트의 길이는 보통 128비트(16바이트) 이상을 권장하며. 암호학적으로 안전한 난수 생성기(csprng)를 통해 생성되어야 합니다.

키 스트레칭(Key Stretching)의 계산적 장벽 구축

솔팅이 공격자의 ‘사전 준비’ 공격을 차단한다면, 키 스트레칭은 ‘실시간 무차별 대입 공격’에 대한 방어 수단입니다. 키 스트레칭은 해시 함수를 단순히 한 번 적용하는 대신, 의도적으로 많은 반복 횟수(워크 팩터)를 통해 해시 계산을 수천에서 수만 번 반복하는 기술입니다. 그래서 합법적인 사용자의 한 번의 로그인 시도는 약 0.1초 정도의 지연을 초래할 수 있지만, 공격자가 수십억 개의 비밀번호 후보를 시도해야 하는 상황에서는 전체 공격 시간을 기하급수적으로 증가시킵니다.

반복 횟수(워크 팩터)의 경제학

키 스트레칭의 효과는 반복 횟수 설정에 달려 있습니다. 이는 보안과 사용자 경험(UX) 사이의 절충안입니다. 너무 낮은 반복 횟수(예: 1,000회 미만)는 현대 하드웨어로 충분히 빠르게 뚫릴 수 있습니다. 반면 너무 높은 반복 횟수(예: 1,000만 회)는 서버 부하를 크게 증가시키고 사용자 로그인 대기 시간을 불편한 수준으로 끌어올릴 수 있습니다. 현실적인 최적화 전략은 하드웨어 성능의 발전에 따라 주기적으로 반복 횟수를 조정하는 것입니다. 예를 들어, 2020년대 중반 기준으로 PBKDF2-HMAC-SHA256의 권장 반복 횟수는 60만 회에서 120만 회 사이입니다. 이 설정은 서버 한 대가 초당 처리할 수 있는 로그인 시도 횟수를 의도적으로 제한함으로써 공격자의 경제적 비용을 극대화합니다.

현대 비밀번호 해싱 알고리즘 비교 분석

솔팅과 키 스트레칭의 원리를 구현한 여러 알고리즘이 존재하며, 각각의 설계 철학과 강점이 다릅니다. 올바른 알고리즘 선택은 시스템의 보안 수준을 결정하는 핵심 요소입니다.

알고리즘 핵심 메커니즘 주요 강점 주의사항 및 한계 권장 워크 팩터 (2020년대 중반)
PBKDF2 (Password-Based Key Derivation Function 2) 솔트 적용 후, 선택한 해시 함수(보통 HMAC-SHA256)를 지정된 횟수만큼 반복 적용. 표준화되어 검증됨(NIST 승인). 구현이 간단하고 광범위한 라이브러리 지원. GPU 공격에 비교적 취약할 수 있음(병렬화 저항성 낮음). 메모리 요구사항이 고정적. 반복 횟수 600,000회 이상
bcrypt 블로피시 암호를 기반으로 한 적응형 해시 함수. 내장된 솔트 및 비용 인자(워크 팩터) 지원. GPU에 의한 병렬 공격에 강함(메모리 접근 패턴 때문). 오랜 기간 실전 검증을 받음. 최대 비밀번호 길이 제한(보통 72바이트)이 있을 수 있음. 메모리 사용량이 알고리즘에 의해 고정됨. 비용 인자 12 이상 (2^12 = 4,096 라운드)
scrypt 계산 뿐만 아니라 메모리 사용량도 의도적으로 크게 만들어 공격 비용을 상승시킴. GPU뿐만 아니라 ASIC/FPGA 공격에도 매우 강력(높은 메모리 대역폭 요구). 많은 메모리를 소비하므로 서버 자원 요구사항이 높음. 매개변수 설정이 복잡할 수 있음. N=2^17, r=8, p=1 (메모리 약 128MB 사용)
Argon2 (2015 Password Hashing Competition 우승) Argon2i(측면 채널 공격 방어), Argon2d(GPU 공격 저항) 등 변종 존재. 시간, 메모리, 병렬 처리 수준을 모두 매개변수로 조정 가능. 현존 최고 수준의 알고리즘으로 평가됨. 다양한 공격 벡터에 대해 균형 잡힌 방어 제공. 유연한 매개변수 튜닝. 상대적으로 새로운 알고리즘(그러나 광범위한 검증 중). bcrypt나 PBKDF2보다 구현체가 덜 보편화될 수 있음. Argon2id: m=194MiB, t=2, p=4

위 표를 분석하면, 레거시 시스템에서 널리 사용되는 PBKDF2는 여전히 단순 반복에 기반한 기본적인 키 스트레칭을 제공반면에, bcrypt는 GPU 공격에, scrypt와 Argon2는 메모리 하드 알고리즘을 통해 더 높은 수준의 공격 비용을 유도합니다. 새로운 시스템을 설계할 때는 가능한 한 Argon2id를 사용하는 것이 현재 보안 업계의 최선의 실천법(Best Practice)으로 권장됩니다.

실전 구현 가이드라인 및 절차

이론적 이해를 바탕으로, 안전한 비밀번호 저장 시스템을 구축하기 위한 구체적인 단계를 제시합니다.

1. 알고리즘 및 매개변수 선택

시스템 요구사항(사용 가능한 서버 자원, 예상 로그인 빈도)을 평가합니다, 새로운 프로젝트라면 argon2id를 우선적으로 고려하십시오. 사용할 수 없다면 bcrypt를 차선책으로 선택합니다. PBKDF2는 호환성이 최우선인 레거시 환경에서만 고려해야 합니다. 매개변수(Argon2의 m, t, p 또는 bcrypt의 비용 인자)는 주기적으로(예: 1-2년마다) 검토하고 하드웨어 성능 향상에 맞춰 조정해야 합니다.

2. 저장 형식 설계

해시 결과를 데이터베이스에 저장할 때는 단순히 해시 값만 저장해서는 안 됩니다. 알고리즘 식별자, 솔트, 워크 팞터, 그리고 최종 해시 값을 모두 포함하는 단일 문자열로 인코딩하는 것이 표준적인 방법입니다. 일반적인 형식은 다음과 같습니다: `$algorithm$parameters$salt$hash`. 예를 들어, `$argon2id$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG`와 같이 저장됩니다. 이 방식은 향후 알고리즘을 업그레이드하거나 매개변수를 변경할 때 이전 해시값과의 호환성을 유지하는 데 필수적입니다.

단순한 해시 함수로 표시된 낡고 금간 방패가 금고를 보호하고 있지만, 현대적인 해킹 도구들이 그 방어를 뚫고 침입하는 모습을 담은 이미지입니다.

3. 검증 프로세스

사용자 로그인 시의 비밀번호 검증 절차는 다음과 같습니다.

  • 사용자가 입력한 비밀번호와 사용자명(또는 이메일)을 받습니다.
  • 데이터베이스에서 해당 사용자의 저장된 해시 문자열을 조회합니다.
  • 문자열에서 알고리즘, 매개변수, 솔트를 파싱합니다.
  • 입력받은 비밀번호와 파싱한 솔트, 동일한 매개변수를 사용하여 동일한 알고리즘으로 해시를 다시 계산합니다.
  • 새로 계산된 해시 값과 데이터베이스에 저장된 해시 값을 상수 시간 비교 함수를 사용하여 비교합니다. 일반적인 문자열 비교(`==`)는 타이밍 공격에 취약할 수 있으므로, 언어가 제공하는 상수 시간 비교 함수(예: PHP의 `hash_equals`, Python의 `hmac.compare_digest`)를 반드시 사용해야 합니다.
  • 두 값이 일치하면 인증 성공, 그렇지 않으면 실패를 반환합니다.

리스크 관리 및 주의사항

가장 강력한 알고리즘도 잘못 구현되면 그 효과가 무력화될 수 있습니다. 다음은 실무에서 반드시 염두에 두어야 할 위험 요소와 대응책입니다.

  • 상수 시간 비교의 생략: 해시 비교 시 일반 문자열 비교 연산자를 사용하면, 첫 번째 불일치 바이트를 발견하는 즉시 비교를 중단하는 최적화로 인해 공격자가 타이밍 공격을 시도할 수 있습니다. 반드시 상수 시간 비교 함수를 사용하여 해시 전체를 비교하는 데 걸리는 시간이 항상 동일하도록 보장해야 합니다.

  • 부적절한 솔트 관리: 솔트를 재사용하거나 예측 가능한 방식으로 생성하는 것은 솔팅의 목적을 훼손합니다. 각 비밀번호에 대해 암호학적으로 안전한 독립적인 난수를 생성해야 합니다.

  • 워크 팩터의 정체: 하드웨어 성능 향상에 따라 과거의 비용 인자는 현재 충분히 빠르게 공격당할 수 있습니다. 정기적인 보안 검토를 통해 워크 팩터를 평가하고, 로그인 시점에 점진적으로 재해싱하는 전략이 필요합니다.

  • 알고리즘에 대한 맹신: Argon2가 현재 최선의 선택지이지만 영원히 안전한 것은 아닙니다. 보안 커뮤니티의 권고를 주시하고, 저장 형식에 알고리즘 식별자를 포함하는 등 유연한 시스템 아키텍처를 설계해야 합니다.

정리하면, 사용자 비밀번호 암호화는 솔팅과 키 스트레칭이라는 두 기둥 위에 세심한 구현과 지속적인 관리가 더해진 종합적인 엔지니어링 영역입니다. 이러한 데이터 보호 로직은 네트워크 수준의 방어 체계와 결합될 때 더욱 견고해집니다.

예를 들어, 가상 네트워크 격리를 위한 터널링 프로토콜의 보안적 이점과 구현 사례에서처럼 해시 데이터가 저장된 데이터베이스 서버를 외부망과 완전히 격리된 가상 사설망(VPC) 내부에 배치하고, 터널링 기술을 통해 인가된 통로로만 접근을 허용한다면 데이터 유출 사고 자체를 미연에 방지할 수 있습니다.

결국 공격자의 경제적 비용을 극대화하는 암호화 기술과 접점 자체를 최소화하는 네트워크 격리 기술이 함께 작동할 때, 사용자 자격 증명을 보호하는 가장 강력한 최종 방어선이 구축됩니다.

Contact Us

자율주행의 미래를 함께 만들어갑니다

최신 자율주행 전기차 및 모빌리티 트렌드를 확인하고, 미래 모빌리티의 혁신적인 변화를 경험하세요.

모든 기사 보기 →