Files
jongryangje/docs/2차인증-TOTP-개발계획.md
2026-04-08 00:23:55 +09:00

134 lines
5.3 KiB
Markdown

# 2차 인증(TOTP) 개발 계획
종량제(쓰레기봉투 물류) 시스템 로그인에 **시간 기반 일회용 암호(TOTP, RFC 6238)** 를 도입하기 위한 계획서입니다.
웹 기능 목록(CSV)의 “로그인 2차 인증” 요구에 대응합니다.
---
## 1. 목표 및 범위
| 구분 | 내용 |
|------|------|
| **목표** | 아이디·비밀번호 이후 **인증 앱(Google/Microsoft Authenticator 등)** 6자리 코드로 2차 검증 |
| **범위** | CodeIgniter 4 앱, `session` 기반 로그인(`Auth`), `member` 테이블 |
| **비범위(초기)** | SMS/이메일 OTP, WebAuthn, 공동인증서 연동 |
---
## 2. 정책(적용 대상)
- **1차 권장:** 관리자 계정만 TOTP **필수**`mb_level` 지자체 관리자(3), super admin(4), 본부 관리자(5)
- **일반 사용자(1)·지정판매소(2):** 초기에는 **미적용 또는 선택 적용** 검토(지원 부담·UX)
- 최종 정책은 보안/감사 요구에 맞춰 `Roles` 또는 설정으로 **한 함수에 모아** 판단 (`needsTotpForMember()` 등)
---
## 3. 사용자 흐름
### 3.1 로그인
1. 기존과 동일: `login_id`, `password`, 승인 상태 검증
2. **TOTP 대상**이고 시크릿이 **등록됨**(`mb_totp_enabled = 1`):
- `logged_in` **세팅하지 않음**
- 세션에 `pending_2fa`, `pending_mb_idx`, (선택) 만료 시각만 저장
- `GET /login/two-factor` 로 이동 → 6자리 입력 → 검증 성공 시 기존과 동일 세션 + `mb_latestdate` 갱신
3. **TOTP 대상**인데 **미등록:**
- 정책 A: 최초 로그인 시 **시크릿 생성 + QR 표시** → 확인 코드 1회 검증 후 `mb_totp_enabled = 1`
- 정책 B: 관리자가 수동으로 등록 유도(별도 화면)
### 3.2 로그아웃
- `pending_2fa` 등 임시 키 **반드시 제거**
### 3.3 인증 앱
- 표준 TOTP 앱이면 동일 시크릿으로 사용 가능(Google / Microsoft Authenticator 등)
---
## 4. 데이터베이스
`member` 테이블에 컬럼 추가(예시):
| 컬럼명 | 타입 | 설명 |
|--------|------|------|
| `mb_totp_secret` | `VARBINARY` 또는 `TEXT` | Base32 시크릿 — **저장 시 암호화** 권장(`encryption.key` 등) |
| `mb_totp_enabled` | `TINYINT(1)` | 0=미사용, 1=등록 완료·로그인 시 검증 대상 |
선택:
- `mb_totp_enabled_at` — 감사
- **백업 코드** — 별도 테이블 또는 컬럼에 **일회용 코드의 해시만** 저장
DDL은 `writable/database/``member_add_totp.sql` 등으로 관리 가능.
---
## 5. 기술 스택
- **TOTP 생성·검증:** Composer 패키지 (예: `spomky-labs/otphp` 또는 `robthree/twofactorauth`)
- **QR(otpauth URI):** 라이브러리 또는 URL 문자열만 표시 후 앱 수동 입력
- **시크릿 보관:** 평문 DB 저장 지양, CI `Encrypter` 또는 기존 PII 암호화 헬퍼와 동일 정책
---
## 6. 코드 변경 요약
| 영역 | 작업 |
|------|------|
| `app/Config/Routes.php` | `login/two-factor` GET·POST, (선택) `setup` 라우트 |
| `app/Controllers/Auth.php` | 로그인 분기, 2단계 검증 액션, 로그아웃 시 pending 제거 |
| `app/Models/MemberModel.php` | `allowedFields` 확장 |
| 신규 뷰 | `auth/login_two_factor.php`, (선택) `auth/totp_setup.php` |
| `app/Config/` | (선택) `Auth.php` 또는 기존 설정에 `requireTotp` 등 |
| `app/Filters/` | `pending_2fa` 상태에서는 보호 URL 접근 불가(원칙상 `logged_in` 없음으로 자연 차단, 허용 화이트리스트만 정리) |
| `writable/database/*.sql` | 마이그레이션/ALTER |
기존 `MemberLogModel`에 “2차 성공/실패” 구분 기록 여부 결정.
---
## 7. 개발 환경에서 2FA 생략
- `.env` 예: `auth.requireTotp = false` (로컬만)
- 운영/스테이징: `true`
- 로직: `비밀번호 검증 성공``needsTotp && config('Auth')->requireTotp` 일 때만 2단계로 보냄
- **운영에 `false`가 배포되지 않도록** CI·배포 체크리스트에 포함
---
## 8. 보안·운영
- TOTP 검증 **실패 횟수 제한** 및 짧은 잠금(브루트포스 방지)
- 시간 윈도우: 라이브러리 기본(예: ±1 step) 및 서버 NTP 권장
- 기기 분실: **백업 코드** 또는 관리자 **시크릿 재발급(감사 로그)** 절차
- `admin_selected_lg_idx` 등 기존 세션은 **2차 완료 후**에만 의미 있게 유지
---
## 9. 테스트 시나리오(초안)
1. TOTP 미등록 관리자 — 등록 플로우 후 로그인 성공
2. TOTP 등록 관리자 — 잘못된 코드 거부, 올바른 코드 성공
3. 일반 사용자 — 정책에 따라 2단계 생략 확인
4. `requireTotp = false` — 개발 모드에서 1단계만으로 `logged_in`
5. 로그아웃 — `pending_2fa` 잔존 없음
---
## 10. 구현 단계(제안)
| 단계 | 내용 |
|------|------|
| **Phase 1** | DB 컬럼, 패키지, 시크릿 생성·저장·검증 유틸, 관리자만 TOTP 필수 |
| **Phase 2** | 등록 UI(QR), 백업 코드 또는 재설정 프로세스 |
| **Phase 3** | 일반 사용자 확대·정책 조정, 로그/감사 보강 |
---
## 11. 참고
- 역할 상수: `app/Config/Roles.php`
- 현재 로그인 완료 지점: `app/Controllers/Auth.php` (세션에 `logged_in` 설정)
- 기존 내부 문서는 `docs/` 에 둘 수 있으나 **현재 `.gitignore`에 포함**되어 저장소에는 올라가지 않음. 팀 저장소 공유용으로 본 파일은 `documentation/` 에 둠.