19 KiB
19 KiB
로그인 & 보안 시스템 구현 계획서 (v1.0)
1. 프로젝트 개요
1.1 목표
- B2B SaaS 환경에서 마스터-사용자 기반 조직 관리
- 이메일 인증 기반 강화된 보안
- 시스템관리자 전체 감시/관리 권한
- 개인정보보호법 준수
1.2 적용 대상
- 30인 미만 소규모 기업 (공용 이메일 허용)
- 개인별 계정 운영 (마스터 승인제)
- 한국 개인정보보호법 준수 필수
2. 계정 유형 및 역할 (3가지)
2.1 마스터 (Master / Company Admin)
정의: 회사 최초 가입자 (회사당 1명 권장, 복수 가능)
권한:
- 회사 정보 입력/수정
- 초대코드 발급 및 관리
- 신규 팀원 가입 승인/거부
- 팀원 목록 조회
- 팀원 강제 제거 (내보내기)
- 회사 구독/결제 관리
- 회사 대시보드 (기본 통계)
DB 구분: users.is_master = true
2.2 팀원 (Member / Regular User)
정의: 마스터가 승인한 회사 소속 사용자
권한:
- 서비스 기능 일반 이용 (B04~B09 워크플로우)
- 개인 프로필 수정
- 프로젝트 생성/수정/조회
DB 구분: users.is_master = false
상태 관리:
PENDING(승인 대기중)ACTIVE(승인됨, 이용 가능)INACTIVE(마스터가 내보냄, 접근 불가)REJECTED(마스터가 거부함)
2.3 시스템관리자 (System Administrator)
정의: 개발사 (Aislo) 측 운영 담당자 = 당신
권한:
- 모든 회사 데이터 조회 (슈퍼유저)
- 회사/사용자 계정 생성/삭제/수정
- 회사별 구독 상태 관리
- 전체 시스템 Q&A/요청사항 처리 (회사 메일로 수신 → 검토/수정/삭제)
- 관리자 대시보드
- 활성 사용자 수
- 하드웨어 리소스 모니터링 (CPU, 메모리, 디스크)
- 소프트웨어 사용 현황 (업로드/다운로드/API 호출 통계)
- 에러/경고 로그 모니터링
- 회사별 파일 저장소 사용량
- 마스터 계정 대체 관리 (마스터 부재 시)
DB 구분: users.role = 'SYSTEM_ADMIN' (별도 테이블로 관리)
접근: 별도 관리 포털 (프론트엔드에서 숨김)
3. 회원가입 및 조직 연결 흐름
3.1 마스터 가입 흐름
1단계: 회원가입 시작
└─ 이메일 입력 (예: founder@gmail.com)
└─ 비밀번호 입력
2단계: 이메일 인증
└─ 시스템이 해당 이메일로 6자리 OTP 코드 발송
└─ 사용자가 OTP 입력하여 인증
3단계: 회사 정보 입력
└─ 회사명
└─ 사업자번호 (선택)
└─ 회사 전화번호
└─ 주소
└─ 대표자명
4단계: 가입 완료
└─ DB에 Company 레코드 생성
└─ 고유 초대코드 자동 생성 (예: ABC-789-XYZ)
└─ users.is_master = true로 설정
└─ 마스터 대시보드로 이동
3.2 팀원 가입 흐름 (요청 기반)
1단계: 팀원이 가입 신청
└─ 이메일 입력 (예: member@gmail.com)
└─ 비밀번호 입력
2단계: 이메일 인증
└─ OTP 입력하여 인증
3단계: 회사 정보 입력 (선택지)
├─ [새 회사 등록하기] → 마스터 역할 시작
└─ [기존 회사에 참여하기] → 4단계로 진행
4단계: 회사 선택/검색
└─ "우리 회사가 이미 가입되어 있나요?"
└─ 회사명으로 검색
└─ 검색 결과에서 해당 회사 선택
5단계: 승인 요청
└─ [가입 신청 보내기] 버튼 클릭
└─ 백엔드: JoinRequest 레코드 생성
└─ 백엔드: 마스터의 등록된 이메일로 승인 메일 발송
6단계: 마스터의 승인 메일 확인
└─ 마스터가 받은 승인 메일:
"홍길동(member@gmail.com)님이 우리 회사에 가입을 신청했습니다.
[승인] [거부] 버튼"
└─ 마스터가 [승인] 클릭
└─ 팀원 users.status = 'ACTIVE'로 변경
└─ 팀원에게 "승인되었습니다" 메일 발송
7단계: 팀원 로그인 가능
└─ 팀원이 이제 서비스에 로그인 가능
💡 핵심 차이점
- ❌ 초대코드 쪽지 방식 아님
- ✅ 사용자가 스스로 요청 → 마스터가 메일로 승인
4. 이메일 인증 (MFA) 정책
4.1 로그인 프로세스
1단계: 아이디(이메일)/비밀번호 입력
2단계: 백엔드 검증 (계정 존재, 비밀번호 일치, 상태 = ACTIVE)
3단계: OTP 발송 및 입력
└─ 등록된 이메일로 6자리 OTP 코드 발송
└─ 사용자 입력 (유효시간: 5분)
4단계: 로그인 완료
└─ JWT/세션 토큰 발급
4.2 이메일 인증 주기
| 상황 | 인증 여부 |
|---|---|
| 최초 가입 시 | ✅ 필수 |
| 로그인할 때마다 | ❌ 아니오 (UX 개선) |
| 3개월 주기 재인증 | ✅ 필수 |
| 새로운 브라우저/기기 | ✅ 필수 |
| 비밀번호 변경 후 | ✅ 필수 |
| 관리자가 강제 로그아웃 | ✅ 필수 (재로그인 시) |
구현 방식:
- DB:
users.last_email_verified_at컬럼 추가 - 로그인 시점에 "마지막 인증이 3개월 이상 지났는가?" 체크
- 맞으면 이메일 인증 강제
5. 세션 관리 정책
5.1 세션 유지 시간
| 시나리오 | 유지 시간 | 이유 |
|---|---|---|
| 기본 세션 유지 | 12시간 | 대용량 파일 업로드 고려 (최대 20GB) |
| 활동 중인 경우 | 연장 | 파일 전송/처리 중일 때는 타임아웃 제외 (마지막 요청으로부터 4시간) |
| 로그인 유지 옵션 | 최대 30일 | (선택사항) 차후 구현 검토 |
5.2 활동 감지 로직
활동으로 간주하는 API 엔드포인트:
- 파일 업로드/다운로드
- 프로젝트 저장
- 데이터 처리 요청
- 대시보드/페이지 조회
세션 연장 방식:
- 각 API 호출 시 last_activity_at 컬럼 업데이트
- 만료 판정:
if (current_time - last_activity_at > 4시간)
→ 세션 자동 만료
else if (current_time - created_at > 12시간)
→ 세션 자동 만료
5.3 세션 만료 처리
- ✅ 프론트엔드: 만료 5분 전 알림 ("5분 후 로그아웃됩니다")
- ✅ 백엔드: 만료 후 모든 요청 거부 (401 Unauthorized)
- ✅ 재로그인 필요
6. 비밀번호 정책 (Google 기준 참고)
6.1 비밀번호 입력 요구사항
| 요구사항 | 기준 |
|---|---|
| 최소 길이 | 8자 이상 |
| 대문자 | A-Z 최소 1개 (필수 아님, 권장) |
| 소문자 | a-z 최소 1개 (필수 아님, 권장) |
| 숫자 | 0-9 최소 1개 (필수 아님, 권장) |
| 특수문자 | !@#$%^&* 등 (필수 아님, 권장) |
정책: Google과 유사하게 "권장이지만 강제하지 않음"
- 이유: 강제 정책은 사용자 이탈 증가
6.2 비밀번호 저장 (DB)
- ❌ 평문 저장 절대 금지
- ✅ bcrypt 또는 PBKDF2 해시 저장
- ✅ Salt 포함 (bcrypt 내장)
- 해시 라운드: 12라운드 이상
6.3 비밀번호 변경
- 이전 비밀번호와 동일하면 거부
- 변경 시 "모든 기기 로그아웃" 옵션 제공 (선택사항)
- 마스터의 경우: 보안상 권장
7. 로그인 이력 및 감시 (Audit Log)
7.1 기록할 정보
로그인 성공:
user_idemaillogin_timestampuser_agent(브라우저명, OS 정보만 - 기기 ID 아님)last_activity_at(업데이트 시작 시점)
로그인 실패:
email(계정 존재 여부 관계없이)failed_timestampfailure_reason(계정없음 / 비밀번호틀림 / 이메일인증실패 / 계정비활성 등)user_agent
프로그램 사용 이력:
user_idaction_type(파일업로드 / 프로젝트저장 / 데이터처리 등)action_timestampresource_id(프로젝트ID, 파일ID 등)status(성공/실패)
7.2 IP 주소 수집 (법적 고려)
❌ 수집하지 않음 (권장)
- 이유: 국내 개인정보보호법상 개인정보이며, 별도 동의 + 암호화 필수
- 법적 리스크 회피
만약 수집한다면:
- ✅ 회원가입 약관에 명시 ("보안 목적으로 로그인 IP 기록")
- ✅ 개인정보 처리방침에 명시 (보관기간: 3개월)
- ✅ DB에 암호화하여 저장 (평문 금지)
- ✅ 마스터/시스템관리자만 조회 가능
현재 권장: IP 수집 제외, User-Agent(브라우저/OS)만 저장
7.3 데이터 보관 기간
| 로그 타입 | 보관 기간 | 자동 삭제 |
|---|---|---|
| 로그인 성공 | 1년 | ✅ 자동 삭제 |
| 로그인 실패 | 6개월 | ✅ 자동 삭제 |
| 프로그램 사용 | 2년 | ✅ 자동 삭제 |
| 삭제된 사용자 로그 | 법적 보유 기간 후 삭제 | ✅ 자동 삭제 |
8. 시스템관리자 대시보드
8.1 기능
📊 시스템 모니터링
- 활성 사용자 수 (실시간)
- 활성 회사 수
- 일일/주간/월간 활동 통계 그래프
💾 리소스 모니터링
-
하드웨어
- CPU 사용률 (%)
- 메모리 사용률 (%)
- 디스크 사용량 (GB)
- 활성 프로세스 수
-
소프트웨어
- 일일 API 호출 수
- 업로드된 총 파일 크기 (GB)
- 다운로드 횟수
- 동시 접속자 수
👥 회사 관리
- 회사 목록 조회 (가입일, 상태, 사용자 수)
- 회사 구독 상태 확인
- 마스터 정보 확인 및 변경
- 회사 삭제 (강제)
👤 사용자 관리
- 전체 사용자 목록
- 사용자 상태 변경 (ACTIVE / INACTIVE / REJECTED)
- 비밀번호 초기화 (관리자용)
- 사용자 로그인 이력 조회
📧 Q&A / 요청사항 관리
- 회사 메일로 수신된 Q&A/요청 목록
- 상태 관리 (NEW / REVIEWED / RESOLVED / DELETED)
- 요청 내용 검토 및 수정
- 요청 삭제 및 히스토리 관리
⚠️ 에러/경고 로그
- 시스템 에러 로그 조회
- 비정상 로그인 시도 (같은 계정 5회 이상 실패)
- 대역폭 초과 경고
- 데이터베이스 에러
9. 보안 방어 로직
9.1 무차별 대입(Brute Force) 공격 방지
로그인 실패 5회 이상 → 계정 15분 잠금
- 로그인 실패 횟수 저장: login_failures (컬럼)
- 마지막 실패 시간: last_failed_at (컬럼)
- 15분 후 자동 해제
시스템관리자에게 알림 (캡파 or SMS)
- 5회 실패 시 시스템 관리자 메일 알림
- 10회 이상 실패 시 경고 레벨 상향
9.2 동시 로그인 처리 (개인별 계정 기준)
- ✅ 동시 로그인 허용
- 이유: 개인별 계정이므로 가정용 + 업무 기기 동시 사용 고려
- 다만, 의심 로그인 시 알림 (예: 다른 국가/지역에서 동시 접속)
9.3 세션 토큰 보안 (확정: Secure HttpOnly 세션 쿠키)
선택: Secure HttpOnly 세션 쿠키 (JWT 아님)
- 이유: 모놀리식 구조 + 중소규모 + 보안 최우선 + 세션 추적 필요
쿠키 설정:
- ✅ 쿠키 이름:
session_id - ✅ 유효 시간: 12시간
- ✅ Secure 플래그: true (HTTPS만 전송)
- ✅ HttpOnly 플래그: true (JS 접근 불가, XSS 방지)
- ✅ SameSite: Lax (CSRF 방지)
세션 저장소: MariaDB sessions 테이블
CREATE TABLE sessions (
id VARCHAR(255) PRIMARY KEY,
user_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NOT NULL,
last_activity_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
10. 이메일 발송 인프라
10.1 발송해야 할 메일 유형
| 메일 타입 | 수신자 | 발송 타이밍 | 중요도 |
|---|---|---|---|
| 가입 확인 메일 | 신규 가입자 | 가입 완료 직후 | 🔴 필수 |
| OTP 인증 코드 | 로그인/재인증 자 | 로그인 시도 직후 | 🔴 필수 |
| 팀원 승인 요청 | 마스터 | 팀원이 가입 신청 시 | 🔴 필수 |
| 가입 승인/거부 결과 | 팀원 | 마스터 승인/거부 직후 | 🟠 중요 |
| 3개월 재인증 알림 | 모든 사용자 | 3개월마다 정기적 | 🟠 중요 |
| 세션 만료 알림 | 활동 중인 사용자 | 만료 5분 전 | 🟡 알림 |
| 비밀번호 변경 알림 | 해당 사용자 | 변경 직후 | 🟡 알림 |
| Q&A 답변 회신 | 문의자 | 시스템 관리자 처리 후 | 🟡 알림 |
10.2 메일 발송 서비스
권장 선택: AWS SES, SendGrid, 또는 한국 국내 서비스 (Solapi, Stibee)
이유:
- 높은 배송 성공률 (99% 이상)
- 빠른 발송 속도 (즉시~1초)
- 스팸 필터 회피 (신뢰도 높음)
- API 기반 통합 용이
구현 방식:
- FastAPI 백엔드에서 비동기 작업 큐 (Celery + Redis)
- 실패한 메일은 재시도 로직 (최대 3회)
11. DB 스키마 (최소 필수 테이블)
11.1 companies 테이블
CREATE TABLE companies (
id INT AUTO_INCREMENT PRIMARY KEY,
company_name VARCHAR(255) NOT NULL,
company_code VARCHAR(20) UNIQUE NOT NULL, -- 초대코드 역할
business_number VARCHAR(20),
phone_number VARCHAR(20),
address VARCHAR(500),
representative_name VARCHAR(100),
master_user_id INT NOT NULL,
status ENUM('ACTIVE', 'INACTIVE', 'SUSPENDED') DEFAULT 'ACTIVE',
subscription_status ENUM('FREE', 'TRIAL', 'PAID', 'EXPIRED') DEFAULT 'FREE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (master_user_id) REFERENCES users(id)
);
11.2 users 테이블
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
company_id INT,
is_master BOOLEAN DEFAULT FALSE,
status ENUM('PENDING', 'ACTIVE', 'INACTIVE', 'REJECTED') DEFAULT 'PENDING',
last_email_verified_at TIMESTAMP,
login_failures INT DEFAULT 0, -- 실패 횟수
last_failed_at TIMESTAMP, -- 마지막 실패 시간
account_locked_until TIMESTAMP, -- 계정 잠금 해제 시간
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (company_id) REFERENCES companies(id)
);
11.3 join_requests 테이블
CREATE TABLE join_requests (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
company_id INT NOT NULL,
status ENUM('PENDING', 'APPROVED', 'REJECTED') DEFAULT 'PENDING',
requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
reviewed_at TIMESTAMP,
reviewed_by INT, -- 마스터 user_id
review_comment TEXT,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (company_id) REFERENCES companies(id),
FOREIGN KEY (reviewed_by) REFERENCES users(id)
);
11.4 login_logs 테이블
CREATE TABLE login_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
email VARCHAR(255), -- 실패 시 user_id가 NULL일 수 있음
status ENUM('SUCCESS', 'FAILURE') NOT NULL,
failure_reason VARCHAR(100),
user_agent TEXT, -- 브라우저, OS 정보만
login_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
INDEX (user_id),
INDEX (login_at)
);
11.5 activity_logs 테이블
CREATE TABLE activity_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
action_type ENUM('FILE_UPLOAD', 'FILE_DOWNLOAD', 'PROJECT_SAVE', 'DATA_PROCESS', 'PAGE_VIEW'),
action_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
resource_id VARCHAR(255), -- 프로젝트/파일 ID
status ENUM('SUCCESS', 'FAILURE') DEFAULT 'SUCCESS',
details JSON, -- 추가 정보
FOREIGN KEY (user_id) REFERENCES users(id),
INDEX (user_id),
INDEX (action_at)
);
11.6 system_admin_logs 테이블
CREATE TABLE system_admin_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
admin_user_id INT NOT NULL,
action_type ENUM('USER_DELETE', 'COMPANY_DELETE', 'QA_MODIFY', 'QA_DELETE', 'RESET_PASSWORD'),
target_id INT, -- 대상 사용자/회사 ID
action_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
details JSON,
FOREIGN KEY (admin_user_id) REFERENCES users(id),
INDEX (admin_user_id),
INDEX (action_at)
);
11.7 support_requests 테이블 (Q&A)
CREATE TABLE support_requests (
id INT AUTO_INCREMENT PRIMARY KEY,
company_id INT,
user_email VARCHAR(255),
subject VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
status ENUM('NEW', 'REVIEWED', 'RESOLVED', 'DELETED') DEFAULT 'NEW',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
reviewed_at TIMESTAMP,
reviewed_by INT, -- 시스템 관리자 user_id
review_notes TEXT,
FOREIGN KEY (company_id) REFERENCES companies(id),
FOREIGN KEY (reviewed_by) REFERENCES users(id),
INDEX (status),
INDEX (created_at)
);
12. 구현 우선순위 (Phase)
Phase 1 (필수): 기본 인증 및 회원가입
- 회원가입 로직 (이메일 OTP 포함)
- 마스터 회사 정보 입력
- 로그인 로직 (비밀번호 + 이메일 OTP)
- 세션/토큰 관리
- 사용자 상태 관리 (ACTIVE/INACTIVE)
Phase 2 (필수): 팀원 가입 승인제
- 팀원 가입 신청 기능
- 가입 요청 알림 메일 (마스터 수신)
- 마스터 승인/거부 대시보드
- 승인/거부 결과 메일 (팀원 수신)
Phase 3 (중요): 보안 강화
- 3개월 주기 재인증 로직
- 로그인 이력 기록 (login_logs)
- 무차별 대입 공격 방지 (5회 실패 잠금)
- 활동 로그 기록 (activity_logs)
Phase 4 (중요): 마스터 관리 기능
- 팀원 목록 조회
- 팀원 강제 내보내기 (status = INACTIVE)
- 마스터 대시보드 (회사 통계)
Phase 5 (고급): 시스템관리자 포털
- 관리자 대시보드
- 회사/사용자 관리
- Q&A 관리
- 리소스 모니터링
- 에러 로그 모니터링
13. 주요 검토 사항
13.1 이메일 발송 인프라
- SMTP 서버 선정 (AWS SES / SendGrid / Solapi)
- 테스트: 가입 메일 발송 성공률 확인
- 스팸 필터 회피 전략 (SPF, DKIM, DMARC 설정)
13.2 비밀번호 해싱 라이브러리
- Python bcrypt 또는 argon2 설정
- 라운드 수 결정 (권장: 12 이상)
13.3 JWT vs 세션 쿠키
- 선택: Secure HttpOnly 쿠키 (권장, CSRF/XSS 방어)
- 토큰 만료 시간 설정
13.4 개인정보 처리방침 작성
- 로그인 이력 수집 목적 명시
- 보관 기간 명시
- 사용자 동의 형식 결정
14. 다음 단계
- ✅ 이 계획서 검토 (당신의 피드백)
- 📝 세부 기술 사양 작성 (.agent/backend.md 업데이트)
- 💻 Phase 1 코드 구현 시작 (회원가입 + 로그인)
- 🧪 단위 테스트 작성
- 🎨 프론트엔드 UI/UX 설계 (.agent/frontend.md)
- 📊 통합 테스트 및 검증
작성일: 2026-07-07
담당자: 시스템 설계 팀
상태: 초안 (v1.0)