Files
jongryangje/docs/기본 개발계획/29-비밀번호_및_개인정보_암호화_기술.md
2026-04-08 00:23:55 +09:00

7.4 KiB

비밀번호 및 개인정보 암호화 기술 정리

본 문서는 종량제(jongryangje) 프로젝트에 실제 적용된 비밀번호 처리와 개인정보(PII) 저장 방식을, 사용 기술·동작 원리·설정·코드 위치 기준으로 정리한다.

관련 코드·설정:

  • app/Controllers/Auth.php — 회원가입 시 비밀번호 해시, 로그인 시 검증
  • app/Controllers/Admin/User.php — 관리자 회원 등록·수정 시 비밀번호 해시
  • app/Helpers/pii_encryption_helper.php — 이메일·연락처 암·복호화
  • app/Config/Encryption.php — CodeIgniter 4 암호화 설정

1. 암호화와 해시의 구분 (이 프로젝트에서의 역할)

구분 대상 데이터 목적 복원 가능 여부
해시 (일방향) 로그인 비밀번호 “같은 비밀번호인지”만 검증 불가 (설계상 원문 복구 불가)
대칭키 암호화 이메일, 연락처 등 DB 유출 시 평문 노출 완화, 화면 표시 시 복호화 가능 (암호화 키 보유 시)

비밀번호는 암호화가 아니라 해시로 저장하는 것이 표준이다. “복호화해서 비교”하지 않고, password_verify로만 비교한다.


2. 비밀번호: PHP password_hash / password_verify

2.1 사용 API

  • 저장(회원가입·비밀번호 변경 시)
    password_hash(평문비밀번호, PASSWORD_DEFAULT)

  • 검증(로그인 시)
    password_verify(입력평문, DB에_저장된_해시문자열)

2.2 PASSWORD_DEFAULT의 의미

  • PHP 버전에 따라 권장 알고리즘이 달라질 수 있으나, 일반적으로 bcrypt 기반 해시를 사용한다.
  • 해시 문자열 내부에 알고리즘 식별자·비용(cost)·salt 등이 한 문자열에 포함되어 저장된다.
  • 따라서 같은 비밀번호로 여러 번 password_hash를 호출해도 매번 다른 해시가 나올 수 있으며, password_verify는 저장된 해시 문자열을 해석해 올바르게 비교한다.

2.3 보안 관점에서의 특징

  • DB가 유출되어도, 공격자가 해시만 가지고 원 비밀번호를 바로 읽어낼 수는 없다 (무차별 대입·레인보우 테이블 등 별도 공격에는 여전히 취약할 수 있으므로 비밀번호 정책·2FA 등은 별도 검토).
  • 애플리케이션은 평문 비밀번호를 DB에 저장하지 않는다.

2.4 프로젝트 내 호출 위치

위치 용도
Auth::register() 가입 시 mb_passwd에 해시 저장
Auth::login() password_verify로 로그인 검증
Admin\User::store() 관리자가 등록한 회원 비밀번호 해시
Admin\User::update() 비밀번호 변경 시에만 새 해시 저장

3. 개인정보(PII): CodeIgniter 4 Encrypter + 커스텀 헬퍼

3.1 적용 필드

app/Helpers/pii_encryption_helper.php 상수 PII_ENCRYPTED_FIELDS 기준:

  • member.mb_email
  • member.mb_phone

mb_id, mb_name 등은 현재 코드 경로상 평문 저장이다. (추가 암호화는 별도 설계·마이그레이션 필요.)

3.2 설정: app/Config/Encryption.php

항목 설명
driver OpenSSL OpenSSL 확장 기반 암호화 핸들러 사용
cipher AES-256-CTR AES 블록암호, 256비트 키, CTR 모드
digest SHA512 프레임워크 내부에서 무결성·키 유도 등에 사용되는 다이제스트 설정 (OpenSSL 핸들러와 연동)
rawData true 암호문을 raw 바이너리로 다룸 (이후 헬퍼에서 base64로 한 번 더 감쌈)
key .envencryption.key 64자리 16진수(hex) 문자열만 유효로 인식 후 hex2bin으로 바이너리 키로 변환. 형식이 맞지 않으면 빈 문자열이 되어 암호화가 비활성화된다.

키 로드 로직 요약:

  • env('encryption.key') → 길이 64이고 모두 16진수인 경우에만 hex2bin 적용.
  • 그 외는 $key === '' 로 간주되어 암호화 미적용 분기로 이어진다.

3.3 AES-256-CTR (개념)

  • AES: 대칭키 블록암호. 같은 키로 암호화·복호화한다.
  • 256: 키 길이(비트). 설정·키 생성 시 이 길이에 맞춰야 한다.
  • CTR (Counter): 블록 모드의 하나. 스트림 암호에 가깝게 동작하며, 같은 키·같은 nonce/IV 재사용만 피하면 안전하게 쓰는 패턴이 널리 쓰인다. (실제 IV/nonce 처리는 CodeIgniter Encrypter 구현에 따름.)

3.4 애플리케이션 레이어: pii_encrypt / pii_decrypt

동작 요약:

  1. 값이 비어 있으면 빈 문자열 반환.
  2. config('Encryption')->key가 비어 있으면 평문 그대로 반환 (키 미설정·개발 편의·기존 데이터 호환).
  3. 키가 있으면 service('encrypter')->encrypt($value) 호출 후, DB 저장용으로
    ENC: + base64_encode(암호문 바이너리) 형태로 만든다.
  4. 복호화 시 ENC: 접두사가 없으면 레거시 평문으로 간주해 그대로 반환.
  5. 예외 발생 시 안전하게 원 입력값을 되돌리는 폴백이 들어 있다 (운영에서는 로깅 정책 별도 검토 권장).

이렇게 하면:

  • DB 덤프를 보더라도 ENC: 로 시작하는 필드는 즉시 읽을 수 있는 평문이 아니다.
  • 복호화에는 애플리케이션이 읽는 동일한 encryption.key 가 필요하다.

3.5 키 로테이션(설정상 지원)

Encryption 설정에 previousKeys 개념이 문서화되어 있다. 키 교체 시 구 데이터 복호화를 위해 이전 키 목록을 두는 용도이며, 실제 운영 적용 여부는 .env 및 CI4 버전 문서와 맞춰 설정해야 한다.


4. 데이터 흐름 요약

4.1 회원가입 (Auth::register)

  1. 비밀번호 → password_hashmember.mb_passwd
  2. 이메일·연락처 → pii_encryptmember.mb_email, member.mb_phone (키 있을 때만 암호문)

4.2 로그인 (Auth::login)

  1. 아이디로 member 조회
  2. password_verify(입력비밀번호, mb_passwd)
  3. 승인 상태 등 추가 정책 후 세션 설정

4.3 관리자 회원 목록·수정 (Admin\User)

  • 목록·수정 폼 표시 전 pii_decrypt로 이메일·연락처 복호화
  • 저장 시 다시 pii_encrypt

5. 운영·보안 체크리스트

  • .envencryption.key 설정
    • 32바이트 난수의 hex 표현 = 64자리 hex (프로젝트 주석 예: php -r "echo bin2hex(random_bytes(32));")
  • .env저장소에 커밋하지 않음 (.env.example에는 키 없이 변수명만)
  • 백업·로그에 복호화된 PII가 불필요하게 남지 않도록 주의
  • 비밀번호는 절대 복호화·로그 출력하지 않음
  • 키 분실 시: 기존 ENC: 데이터는 복구 불가에 가깝다 → 키 관리 절차 필요

6. 참고 문서


7. 변경 이력

  • 최초 작성: 프로젝트 코드(Auth, User, pii_encryption_helper, Config\Encryption) 기준 정리