7.4 KiB
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_emailmember.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 |
.env의 encryption.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
동작 요약:
- 값이 비어 있으면 빈 문자열 반환.
config('Encryption')->key가 비어 있으면 평문 그대로 반환 (키 미설정·개발 편의·기존 데이터 호환).- 키가 있으면
service('encrypter')->encrypt($value)호출 후, DB 저장용으로
ENC:+ base64_encode(암호문 바이너리) 형태로 만든다. - 복호화 시
ENC:접두사가 없으면 레거시 평문으로 간주해 그대로 반환. - 예외 발생 시 안전하게 원 입력값을 되돌리는 폴백이 들어 있다 (운영에서는 로깅 정책 별도 검토 권장).
이렇게 하면:
- DB 덤프를 보더라도
ENC:로 시작하는 필드는 즉시 읽을 수 있는 평문이 아니다. - 복호화에는 애플리케이션이 읽는 동일한
encryption.key가 필요하다.
3.5 키 로테이션(설정상 지원)
Encryption 설정에 previousKeys 개념이 문서화되어 있다. 키 교체 시 구 데이터 복호화를 위해 이전 키 목록을 두는 용도이며, 실제 운영 적용 여부는 .env 및 CI4 버전 문서와 맞춰 설정해야 한다.
4. 데이터 흐름 요약
4.1 회원가입 (Auth::register)
- 비밀번호 →
password_hash→member.mb_passwd - 이메일·연락처 →
pii_encrypt→member.mb_email,member.mb_phone(키 있을 때만 암호문)
4.2 로그인 (Auth::login)
- 아이디로
member조회 password_verify(입력비밀번호, mb_passwd)- 승인 상태 등 추가 정책 후 세션 설정
4.3 관리자 회원 목록·수정 (Admin\User)
- 목록·수정 폼 표시 전
pii_decrypt로 이메일·연락처 복호화 - 저장 시 다시
pii_encrypt
5. 운영·보안 체크리스트
.env에encryption.key설정- 32바이트 난수의 hex 표현 = 64자리 hex (프로젝트 주석 예:
php -r "echo bin2hex(random_bytes(32));")
- 32바이트 난수의 hex 표현 = 64자리 hex (프로젝트 주석 예:
.env는 저장소에 커밋하지 않음 (.env.example에는 키 없이 변수명만)- 백업·로그에 복호화된 PII가 불필요하게 남지 않도록 주의
- 비밀번호는 절대 복호화·로그 출력하지 않음
- 키 분실 시: 기존
ENC:데이터는 복구 불가에 가깝다 → 키 관리 절차 필요
6. 참고 문서
- 동일 레포 내 설계 방향:
docs/기본 개발계획/19-db-personal-data-encryption.md - PHP: password_hash, password_verify
- CodeIgniter 4: Encryption 서비스
7. 변경 이력
- 최초 작성: 프로젝트 코드(
Auth,User,pii_encryption_helper,Config\Encryption) 기준 정리