66. 비밀번호 암호화 저장 방식 (일방향 해시 및 솔팅) 감리

⚠️ 이 문서는 시스템 감리 시 가장 빈번하고 치명적으로 지적되는 보안 결함인 "사용자의 비밀번호를 데이터베이스(DB)에 어떻게 저장하고 있는가?"에 대해, 평문 저장은 물론 복호화 가능한 양방향 암호화를 엄격히 금지하고 오직 '단방향 해시(Hash) + 솔트(Salt)' 방식만을 허용하는 법적/기술적 검증 과정을 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 데이터베이스 관리자(DBA)나 해커가 DB를 통째로 탈취하더라도, 그 안에 저장된 비밀번호의 원래 값을 지구상의 어떤 컴퓨터로도 영원히 알아낼 수 없게(비가역성) 만드는 암호학적 파괴 저장 기법이다.
  2. 가치: 개인정보보호법 및 ISMS 인증 심사의 '필수(Mandatory)' 통과 요건이다. 만약 비밀번호가 평문이나 MD5 같은 구형 알고리즘으로 저장된 것이 적발되면 해당 시스템은 즉시 서비스 오픈이 중단된다.
  3. 기술 체계: 감리인은 소스코드를 열어 비밀번호 저장 로직이 SHA-256 이상의 안전한 해시 함수를 사용했는지, 그리고 동일한 비밀번호가 같은 암호문으로 변환되어 유추당하는 것(레인보우 테이블 공격)을 막기 위해 난수(Salt)를 섞어 쳤는지 철저히 점검한다.

Ⅰ. 비밀번호 저장의 3대 금기 사항

감리인이 DB 테이블과 소스코드를 열었을 때 다음 3가지 중 하나라도 발견되면 즉시 '중결함' 처리된다.

  1. 평문 (Plaintext) 저장:
    • password 컬럼에 1234apple이라는 글자가 그대로 적혀있는 최악의 상태. 해커는 물론이고 내부 직원도 고객의 비밀번호를 볼 수 있어 개인정보보호법 위반 1순위다.
  2. 양방향 암호화 (Two-way Encryption):
    • AES-256 같은 훌륭한 암호화 알고리즘을 썼더라도 비밀번호 저장 용도로는 '불합격'이다.
    • 양방향 암호화는 복호화 키(Key)만 있으면 다시 원래의 글자(1234)로 되돌릴 수 있기 때문이다. 시스템 관리자조차도 고객의 진짜 비밀번호를 알아낼 방법이 없어야(일방향) 합법이다.
  3. 구형 해시 알고리즘 (MD5, SHA-1):
    • 일방향(단방향) 암호화를 썼더라도 MD5나 SHA-1 같은 낡은 함수는 감리에서 반려된다.
    • 최신 그래픽카드(GPU)의 연산 속도로는 몇 분 만에 해시값이 충돌하는 취약점을 찾아내 원래 글자를 유추해 낼 수 있기 때문이다. 반드시 SHA-256 이상의 길이를 요구한다.

📢 섹션 요약 비유: 고객의 집 열쇠(비밀번호)를 보관할 때, 열쇠를 그대로 서랍에 넣는 것(평문)이나 나중에 자물쇠를 풀 수 있게 금고에 넣어두는 것(양방향)은 모두 불법입니다. 합법적인 유일한 방법은 열쇠를 용광로에 녹여 쇳물(해시)로 만들어 보관하다가, 나중에 고객이 열쇠를 가져오면 똑같이 용광로에 녹여보고 쇳물의 모양이 똑같은지만 대조하는(단방향) 방식뿐입니다.


Ⅱ. 소스코드 감리 포인트: 단방향 해시와 솔팅(Salting)

단순한 SHA-256 적용만으로는 부족하다. 감리인은 '소금(Salt)'을 쳤는지 검사한다.

  1. 레인보우 테이블 (Rainbow Table) 공격:
    • 1234라는 글자를 SHA-256으로 해시하면 언제나 03ac6742... 라는 동일한 결괏값이 나온다.
    • 해커들은 자주 쓰이는 비밀번호 1억 개의 해시값을 미리 다 계산해서 사전(Table)으로 만들어두었다. 해커가 DB를 털었을 때 03ac...라는 값이 보이면 사전을 뒤져 "아, 이놈 비밀번호는 1234구나"라고 1초 만에 알아낸다.
  2. 솔트 (Salt) 추가 적용 여부 점검:
    • 이 공격을 막기 위해 감리인은 소스코드에 **"비밀번호 원문에 무작위 난수(Salt)를 섞어서 해시하는 로직"**이 있는지 확인한다.
    • Hash("1234" + "f7d8a9") = 5b9d...
    • 이렇게 하면 비밀번호가 1234로 똑같은 두 명의 사용자라도 DB에 저장되는 해시값이 완전히 달라져, 해커가 만들어둔 레인보우 테이블 사전이 무용지물이 된다.
  3. 키 스트레칭 (Key Stretching):
    • 추가로 감리인은 해시 함수를 1번만 돌렸는지, 아니면 수천 번 반복해서(PBKDF2, bcrypt, scrypt 사용) 돌렸는지 점검한다. 해시를 1만 번 반복하면 해커가 사전 공격을 시도할 때 연산 속도가 너무 느려져 해킹을 물리적으로 포기하게 만들 수 있다.

📢 섹션 요약 비유: 비밀번호 1234를 그냥 고기라고 할 때, 고기를 그대로 구우면(단순 해시) 요리사(해커)가 먹어보고 무슨 고기인지 단박에 알아챕니다. 하지만 구울 때마다 무작위로 엄청난 양의 소금과 후추(Salt)를 팍팍 치고, 1만 번씩 망치로 다져버리면(키 스트레칭), 이게 소고기였는지 돼지고기였는지 절대 유추할 수 없게 만드는 철통 방어 레시피입니다.


Ⅲ. 감리인의 시정 조치 및 이행 확인

발견된 결함은 서비스 오픈 전 반드시 고쳐져야 한다.

  1. 기존 데이터 마이그레이션:
    • 감리 중 평문 비밀번호가 적발되면, 개발팀은 단순히 앞으로 가입하는 사람만 암호화하는 코드로 수정해선 안 된다.
    • 감리인은 **"기존 DB에 쌓여있던 10만 명의 평문 비밀번호까지 모두 단방향 해시로 일괄 변환(Update) 조치했는가?"**를 데이터베이스 덤프를 통해 최종 확인한다.
  2. 비밀번호 분실 찾기 로직 점검:
    • 일방향 암호화를 제대로 적용했다면, 사용자가 "비밀번호 찾기"를 눌렀을 때 기존 비밀번호를 이메일로 보내주는 것은 불가능하다. (관리자도 모르기 때문)
    • 감리인은 **"비밀번호를 알려주지 않고, 임시 비밀번호를 발급하거나 새 비밀번호로 '재설정(Reset)'하도록 화면과 로직이 올바르게 설계되었는가?"**를 기능 테스트(Functional Test)로 증명해야 한다.

📢 섹션 요약 비유: 감리인은 식당의 위생 상태를 적발하는 것에 그치지 않고, "기존에 만들어둔 상한 음식(과거 평문 데이터)을 몽땅 폐기했는지", 그리고 "손님이 예전 영수증을 달라고 할 때 시스템 구조상 절대 줄 수 없게(재설정만 가능) 올바르게 매뉴얼이 수정되었는지" 끝까지 확인하여 재발을 막는 역할을 수행합니다.