diff --git a/ideas/250815_로그인_인증_시스템_보안_개선_필요사항.md b/ideas/250815_로그인_인증_시스템_보안_개선_필요사항.md new file mode 100644 index 0000000..9a21dce --- /dev/null +++ b/ideas/250815_로그인_인증_시스템_보안_개선_필요사항.md @@ -0,0 +1,212 @@ +# 로그인 인증 시스템 보안 개선 필요사항 + +작성일: 2025-08-15 +작성자: Claude & happybell80 +상태: 아이디어 → 긴급 개선 필요 +관련: auth-server, robing-gateway, frontend + +## 개요 + +현재 로빙 프로젝트의 인증 시스템에서 JWT 토큰은 발급되지만 실제 API 호출 시 검증되지 않는 심각한 보안 취약점이 발견되었습니다. 누구나 X-User-Id 헤더를 조작하여 다른 사용자로 위장할 수 있는 상태입니다. + +## 현재 인증 흐름 + +``` +1. Frontend → auth-server로 리다이렉트 (/auth/gmail/login) + ↓ +2. Auth-server → Google OAuth → 콜백 받음 + ↓ +3. Auth-server → Redis에 임시 코드 저장 → Frontend로 리다이렉트 (#code=xxx) + ↓ +4. Frontend → 코드로 토큰 교환 (/auth/verify) → JWT 토큰 받음 + ↓ +5. Frontend → localStorage에 토큰 저장 + ↓ +6. Frontend → robing-gateway 호출 시 X-User-Id 헤더만 전송 ⚠️ + ↓ +7. robing-gateway → 토큰 검증 없이 X-User-Id 신뢰 ⚠️ +``` + +## 발견된 보안 취약점 + +### 1. 인증 토큰 미전달 +- **현상**: Frontend가 JWT 토큰을 저장하지만 API 호출 시 전송하지 않음 +- **코드 위치**: frontend의 API 클라이언트 +- **영향**: 인증 메커니즘이 무의미함 + +### 2. 토큰 검증 부재 +- **현상**: robing-gateway가 X-User-Id 헤더만 확인하고 JWT 검증 없음 +- **코드 예시**: + ```python + # 현재 (취약함) + user_id = request.headers.get("X-User-Id", "default") + + # 필요한 것 + token = request.headers.get("Authorization", "").replace("Bearer ", "") + user_id = verify_jwt_token(token) # 검증 필요! + ``` +- **영향**: 누구나 헤더 조작으로 다른 사용자 행세 가능 + +### 3. 시스템 간 연결 끊김 +- **auth-server**: JWT 발급 기능 있음 (51123 서버, 포트 9000) +- **robing-gateway**: JWT 검증 기능 없음 (51124 서버) +- **frontend**: 토큰 보유하지만 전송 안 함 +- **영향**: 인증 시스템이 형식적으로만 존재 + +### 4. 기본값 폴백 문제 +- **현상**: X-User-Id 없으면 "default"로 처리 +- **영향**: 모든 미인증 사용자가 동일한 로빙/데이터 공유 + +## 긴급 수정 필요사항 + +### Frontend 수정 +```javascript +// API 클라이언트에 토큰 헤더 추가 +const apiCall = async (endpoint, data) => { + const token = localStorage.getItem('auth_token'); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': token ? `Bearer ${token}` : '' // 추가! + }; + // ... +}; +``` + +### robing-gateway 수정 +```python +# JWT 검증 미들웨어 추가 +from jose import jwt, JWTError + +async def verify_token(request: Request): + token = request.headers.get("Authorization", "").replace("Bearer ", "") + if not token: + raise HTTPException(status_code=401, detail="Token missing") + + try: + payload = jwt.decode(token, JWT_SECRET, algorithms=["HS256"]) + request.state.user_id = payload.get("sub", "default") + except JWTError: + raise HTTPException(status_code=401, detail="Invalid token") + + return request.state.user_id + +@app.post("/api/chat") +async def chat(request: Request): + user_id = await verify_token(request) # 검증 필수! + # ... +``` + +### 시스템 간 연동 +1. **JWT 시크릿 공유**: auth-server와 robing-gateway가 동일한 JWT_SECRET 사용 +2. **환경변수 설정**: + ```bash + # .env 파일 + JWT_SECRET=동일한_시크릿_키_사용 + JWT_ALGORITHM=HS256 + JWT_EXPIRY_HOURS=24 + ``` + +### 에러 처리 +```python +# 인증 실패 시 명확한 에러 +@app.exception_handler(401) +async def unauthorized_handler(request, exc): + return JSONResponse( + status_code=401, + content={"error": "Authentication required", "detail": str(exc)} + ) +``` + +## 추가 개선사항 + +### 1. Refresh Token 구현 +```python +# 장기 세션 유지를 위한 refresh token +def create_tokens(user_id: str): + access_token = create_jwt(user_id, expires_in=timedelta(hours=1)) + refresh_token = create_jwt(user_id, expires_in=timedelta(days=30)) + return access_token, refresh_token +``` + +### 2. 토큰 블랙리스트 +```python +# Redis를 활용한 로그아웃 토큰 관리 +async def logout(token: str): + await redis.setex(f"blacklist:{token}", JWT_EXPIRY_HOURS * 3600, "1") + +async def is_token_blacklisted(token: str): + return await redis.exists(f"blacklist:{token}") +``` + +### 3. Role-Based Access Control (RBAC) +```python +# JWT에 역할 정보 포함 +payload = { + "sub": user_id, + "email": user_email, + "role": "admin", # or "user", "guest" + "permissions": ["read", "write", "delete"] +} +``` + +## 서버별 현황 + +### 51123 서버 +- **auth-server** 실행 중 (포트 9000) +- JWT 발급 기능 정상 +- Redis 임시 코드 시스템 작동 + +### 51124 서버 +- **robing-gateway** 실행 중 +- JWT 검증 로직 없음 ⚠️ +- 모든 로빙 서비스 운영 + +### 로컬 개발 +- **frontend** 개발 +- 토큰 저장은 하지만 전송 안 함 ⚠️ + +## 보안 위험 수준 + +**🔴 Critical (긴급)** + +현재 상태에서는: +1. 누구나 다른 사용자로 위장 가능 +2. 개인 데이터 접근 가능 +3. 로빙 설정 변경 가능 +4. 실질적인 인증 보호 없음 + +## 구현 우선순위 + +1. **즉시 (1일 내)** + - robing-gateway에 JWT 검증 추가 + - Frontend API 호출 시 토큰 헤더 추가 + +2. **긴급 (1주 내)** + - JWT 시크릿 환경변수 통일 + - 에러 처리 및 로깅 추가 + +3. **중요 (2주 내)** + - Refresh token 구현 + - 토큰 블랙리스트 관리 + - RBAC 권한 시스템 + +## 테스트 체크리스트 + +- [ ] Frontend에서 Authorization 헤더 전송 확인 +- [ ] robing-gateway JWT 검증 동작 확인 +- [ ] 잘못된 토큰 시 401 에러 반환 +- [ ] 토큰 없을 시 적절한 에러 메시지 +- [ ] 토큰 만료 시 재로그인 유도 +- [ ] 로그아웃 시 토큰 무효화 + +## 참고사항 + +- JWT 라이브러리: python-jose (이미 사용 중) +- Redis: 임시 코드 및 블랙리스트 관리 +- 환경변수: JWT_SECRET 반드시 동일하게 설정 + +--- + +**"인증은 시스템의 문지기입니다. 문이 열려있다면 의미가 없습니다."** + +이 문제는 즉시 수정이 필요한 보안 취약점입니다. \ No newline at end of file