# 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/` 에 둠.