89 lines
5.8 KiB
Markdown
89 lines
5.8 KiB
Markdown
# DB 개인정보 보안·암호화 방안 (개발자도 알 수 없게)
|
|
|
|
“DB 보안을 중요시하고, **개발자도 사용자 개인정보를 알 수 없게** 꼼꼼히 암호화한다”는 요구에 맞춘 설계·구현 방향입니다.
|
|
|
|
---
|
|
|
|
## 1. 목표
|
|
|
|
- **DB에 저장되는 개인정보**를 **암호화**해, DB만 접근하는 사람(개발자, DBA, 백업 유출 시)이 **평문을 볼 수 없게** 한다.
|
|
- **암호화 키**는 DB나 소스코드 저장소에 두지 않고, **환경 변수·시크릿 관리**에만 둔다.
|
|
- 비밀번호는 **해시만** 저장(복호화 불가). 이름·휴대전화·이메일 등 **복구가 필요한 값**만 **대칭키 암호화**로 저장한다.
|
|
|
|
---
|
|
|
|
## 2. 무엇을 어떻게 다룰지
|
|
|
|
| 데이터 종류 | 처리 방식 | 이유 |
|
|
|-------------|------------|------|
|
|
| **비밀번호** | **해시만** (`password_hash` / bcrypt·argon2) | 복호화 불필요. 로그인 시 `password_verify`만 하면 됨. DB 유출돼도 평문 복원 불가. |
|
|
| **이름, 휴대전화, 이메일** 등 | **저장 전 암호화**, 조회 시 **애플리케이션에서만 복호화** | DB에는 암호문만 저장. 키가 없으면 개발자도 평문을 알 수 없음. |
|
|
| **로그·감사 이력** | 개인정보 필드는 **암호화 저장** 또는 **마스킹만 저장** | 로그에 평문 개인정보가 쌓이지 않게 함. |
|
|
|
|
---
|
|
|
|
## 3. 필드 단위 암호화 (이름·전화·이메일)
|
|
|
|
### 3.1 방식
|
|
|
|
- **대칭키 암호화**(예: **AES-256-GCM** 또는 AES-256-CBC + HMAC) 사용.
|
|
- **키**는 PHP `openssl` 등으로 생성해, **애플리케이션만** 사용. DB에는 키를 저장하지 않음.
|
|
- **IV(초기화 벡터)** 는 암호화할 때마다 랜덤 생성하고, **암호문과 함께 저장** (IV는 공개돼도 됨, 키만 비밀).
|
|
|
|
### 3.2 키 보관 (개발자도 알 수 없게)
|
|
|
|
- **로컬/개발**: `.env`에 `ENCRYPTION_KEY=...` 형태로 둠. **`.env`는 Git에 넣지 않고**, `.env.example`에는 키 없이 변수명만 예시로 둠.
|
|
- **운영**: 서버 환경 변수 또는 **시크릿 관리**(AWS Secrets Manager, HashiCorp Vault, 네이버 클라우드 시크릿 등)에 넣고, 앱 기동 시에만 읽어 씀.
|
|
- **규칙**: 키가 **소스코드·DB·백업 파일**에 들어가지 않도록 한다. 개발자에게 DB만 주면 **암호문만 보이고**, 키 없이는 복호화 불가.
|
|
|
|
### 3.3 적용 위치 (CI4 예시)
|
|
|
|
- **옵션 A**: **암호화 헬퍼/라이브러리**를 두고, **Model**에서 `member` 등 저장·조회 시:
|
|
- **INSERT/UPDATE 전**: `mb_name`, `mb_phone`, `mb_email` 등을 암호화해 DB에 넣음.
|
|
- **SELECT 후**: 화면·비즈니스 로직에 넘기기 직전에만 복호화. 로그에는 복호화된 값이나 평문을 남기지 않음.
|
|
- **옵션 B**: **Entity**에서 `mb_name` 등 접근 시 자동 암·복호화(Getter/Setter에서 처리). Model은 Entity를 쓰므로, 저장·조회 시 일관되게 암호화된 값만 DB에 쌓이게 함.
|
|
|
|
이렇게 하면 **DB 덤프를 열어도** 이름·전화·이메일은 **암호문**으로만 보이고, **키를 모르는 개발자**는 평문을 알 수 없다.
|
|
|
|
### 3.4 키 로테이션(선택)
|
|
|
|
- 주기적으로 **새 키**로 다시 암호화하는 정책. 구현 시 **키 버전**을 필드에 두고, 복호화 시 버전별 키로 풀 수 있게 하면 된다. 초기에는 단일 키로 시작해도 됨.
|
|
|
|
---
|
|
|
|
## 4. 비밀번호는 암호화가 아니라 해시
|
|
|
|
- **저장**: `password_hash($password, PASSWORD_DEFAULT)` (bcrypt 등)로 **해시만** 저장.
|
|
- **검증**: `password_verify($input, $storedHash)`.
|
|
- **복호화하지 않음**. 따라서 “개발자가 DB만 보고 비밀번호를 알 수 없다”는 건 해시를 쓰는 것만으로 만족됨. 이미 11번 문서 등에서 `password_verify` 전제로 되어 있음.
|
|
|
|
---
|
|
|
|
## 5. 비식별화(마스킹)와의 관계
|
|
|
|
- **PWB-010201-001** “이름·휴대전화 가림”은 **화면·로그에 보여줄 때** 마스킹(홍*동, 010-****-5678)하는 **비식별화**이다.
|
|
- **DB 보안**을 위해선 그에 **더해** 위처럼 **저장 단계에서 암호화**를 하는 것이 좋다.
|
|
- 저장: 암호화 → DB에는 암호문만.
|
|
- 표시: 필요한 경우에만 복호화 후, 권한에 따라 **마스킹**해서 보여줌 (관리자만 전체 보기 등 정책에 따라).
|
|
|
|
---
|
|
|
|
## 6. 접근 제어·운영
|
|
|
|
- **DB 계정**: 애플리케이션 전용 계정만 최소 권한(SELECT/INSERT/UPDATE/DELETE 등 필요한 것만) 부여. 개발·운영 DB는 역할별로 분리하고, **개인정보가 있는 테이블**에 대한 직접 조회를 제한할 수 있으면 좋음.
|
|
- **백업**: 백업 파일도 **암호문**만 포함하므로, 키가 유출되지 않는 한 개인정보 평문이 노출되지 않음. 백업 파일 자체도 암호화 저장 권장.
|
|
- **감사 로그**: 개인정보 조회/복호화 이벤트를 로그에 남기면, 나중에 “누가 언제 복호화했는지” 추적 가능. (구현 여부는 정책에 따라.)
|
|
|
|
---
|
|
|
|
## 7. 구현 시 체크리스트
|
|
|
|
- [ ] 개인정보 필드(mb_name, mb_phone, mb_email 등) **저장 전 AES-256 등으로 암호화**.
|
|
- [ ] **암호화 키**는 `.env` 또는 시크릿 관리에만 두고, **Git/DB에 포함하지 않음**.
|
|
- [ ] 비밀번호는 **해시만** 저장, 복호화 로직 없음.
|
|
- [ ] 복호화는 **애플리케이션에서만**, 필요한 권한이 있을 때만 수행. 로그에는 평문·복호화 결과를 남기지 않음.
|
|
- [ ] 화면·로그에는 필요 시 **마스킹(비식별화)** 적용.
|
|
- [ ] (선택) 키 로테이션·감사 로그 설계.
|
|
|
|
이렇게 하면 “개발자도 사용자 개인정보를 알 수 없게” DB 보안을 꼼꼼히 맞추는 방향이 됩니다. 구현은 Phase 1 후반 또는 Phase 2에서 **암호화 라이브러리/헬퍼 도입**과 **member 등 개인정보 테이블 적용**부터 진행하면 됩니다.
|