# 로그인 인증 시스템 보안 개선 필요사항 작성일: 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 수정 ### robing-api.ts 수정 필요 ```typescript // 현재 문제: 토큰 전송 안 함, 하드코딩된 userId export async function sendMessage(text: string, userId: string = 'test_user'): Promise { const response = await fetch(`${ROBING_API_URL}/api/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-User-Id': userId // ❌ 토큰 없음, 조작 가능 }, body: JSON.stringify({ message: text, user_id: userId }) }); } // 수정 필요 export async function sendMessage(text: string, token: string, userId: string): Promise { const response = await fetch(`${ROBING_API_URL}/api/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, // ✅ JWT 토큰 추가 'X-User-Id': userId // 호환성 유지 (임시) }, body: JSON.stringify({ message: text, user_id: userId }) }); } ``` ### chat-interface.tsx 수정 필요 ```typescript // 현재: useAuth 사용 안 함 import { sendMessage } from '@/services/robing-api'; // 수정 필요 import { useAuth } from '@/contexts/auth-context'; const ChatInterface = () => { const { user, isAuthenticated } = useAuth(); const handleSend = async (input: string) => { if (!isAuthenticated || !user) { // 로그인 유도 return; } const token = localStorage.getItem('auth_token'); const response = await sendMessage(input, token, user.id); }; }; ``` ### 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 임시 코드 시스템 작동 - ✅ pydantic BaseSettings 사용 ### 51124 서버 - **robing-gateway** 실행 중 - JWT 검증 로직 없음 ⚠️ - 모든 로빙 서비스 운영 - ❌ **config.py 없음** - os.getenv() 분산 사용 (database.py에서 직접 호출) ### 로컬 개발 - **frontend** 개발 - 토큰 저장은 하지만 전송 안 함 ⚠️ - API URL 문제: `https://ro-being.com/rb10508` 대신 Gateway URL 사용 필요 ### 설정 관리 표준화 필요 | 서비스 | Config 위치 | 상태 | |--------|------------|------| | rb10508_micro | app/config.py | ✅ 표준 | | rb8001 | app/core/config.py | ✅ 표준 | | skill-slack | app/core/config.py | ✅ 표준 | | robing-gateway | **없음** | ❌ 비표준 | robing-gateway도 BaseSettings 패턴으로 전환 필요 ## 보안 위험 수준 **🔴 Critical (긴급)** 현재 상태에서는: 1. 누구나 다른 사용자로 위장 가능 2. 개인 데이터 접근 가능 3. 로빙 설정 변경 가능 4. 실질적인 인증 보호 없음 ## 서버팀 관점 분석 ### 🚨 현재 상황: 치명적 보안 취약점 인증 시스템이 껍데기만 있고 실제로는 작동하지 않는 상태입니다. ### 핵심 문제 요약 1. **토큰은 있는데 쓰지 않음** - Frontend: JWT 받아서 localStorage에 저장만 함 - API 호출 시: Authorization 헤더 없이 X-User-Id만 전송 2. **검증 없이 믿음** - robing-gateway: X-User-Id 헤더만 보고 "아, 이 사람이구나" 믿음 - 마치 신분증 검사 없이 "저 김철수입니다" 하면 믿는 것 3. **시스템 단절** - 51123: auth-server (JWT 발급) - 51124: robing-gateway (JWT 검증 코드 없음) - 서로 JWT_SECRET도 공유 안 함 ### 실제 해킹 시연 누구나 5초면 해킹 가능: ```bash curl -X POST https://ro-being.com/api/chat \ -H "X-User-Id: happybell80" \ -d '{"message": "비밀번호 알려줘"}' ``` ### 즉시 필요한 조치 (24시간 내) 1. robing-gateway에 JWT 검증 미들웨어 추가 2. Frontend API 클라이언트에 Authorization 헤더 추가 3. JWT_SECRET 환경변수 통일 ### 기술적 판단 - **난이도**: 낮음 (코드 10-20줄) - **영향도**: 극대 - **작업 시간**: 2-3시간 ### 의문점 1. 왜 처음부터 이렇게 만들었을까? 2. 테스트 중이라 일부러 풀어놓은 건가? 3. 아니면 단순 실수? ### 결론 > "자물쇠는 있는데 열쇠 구멍이 막혀있는 상태" 지금 당장 고치지 않으면 모든 사용자 데이터가 위험합니다. 51124 서버만으로는 수정 불가능하고, 23 서버와 로컬 개발자의 즉각적인 협업이 필요합니다. ## 구현 우선순위 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 반드시 동일하게 설정 --- **"인증은 시스템의 문지기입니다. 문이 열려있다면 의미가 없습니다."** 이 문제는 즉시 수정이 필요한 보안 취약점입니다.