# JWT 인증 체계 개선 - Slack 아이템화 ## 상태: 대부분 해결됨 (2025-08-28) ## 해결: Gateway, rb8001, skill-email JWT 검증 구현 ✅ --- ## 1. 문제 요약 ### ✅ 대부분 해결됨 **JWT 인증 구현 상태** - **웹 경로**: JWT + UUID 사용 ✅ (rb8001 /api/message) - **Slack 경로**: Slack 서명 검증 + UUID 변환 ✅ - **서비스 간 통신**: JWT 인증 추가됨 ✅ (skill-email) - **Gateway**: /api/stats 엔드포인트 JWT 검증 추가 ✅ ### 해결된 보안 개선사항 - ~~**인증 우회**: 헤더 조작으로 다른 사용자 행세 가능~~ ✅ JWT 검증으로 해결 - ~~**데이터 접근**: 타인의 이메일, 통계 등 민감 정보 접근 가능~~ ✅ 인증 필수화 - ~~**무결성 파괴**: 사용자 식별 체계 불일치로 데이터 오염~~ ✅ UUID 통합 --- ## 2. 서비스별 현황 분석 ### 2.1 JWT 인증 구현 상태 | 서비스/엔드포인트 | JWT 인증 | user_id 처리 | 현재 상태 | |-------------------|---------|--------------|----------| | **rb8001 /api/message** | ✅ 구현 (2025-08-28) | UUID (JWT sub) | 정상 | | **rb8001 /api/slack/events** | ❌ 없음 | Slack ID → UUID 변환 | Slack 전용 | | **rb8001 /complete** | ❌ 없음 | "external_service" 고정 | 내부 API | | **rb10508_micro** | ❌ 없음 | ~~X-User-Id 헤더 신뢰~~ | 폐기 예정 | | **skill-email** | ✅ 구현 (2025-08-28) | JWT 검증 추가 | 해결됨 | | **skill-news** | ❌ 없음 | 미사용 중 | - | ### 2.2 Frontend API 호출 패턴 | 엔드포인트 | Frontend에서 보내는 헤더 | Gateway 검증 | |--------------|------------------------|-------------| | `/api/chat` | Authorization + X-User-Id | JWT 검증 ✅ | | `/api/history` | Authorization + X-User-Id | JWT 검증 ✅ | | `/api/items/gmail` | Authorization + X-User-Id | JWT 검증 ✅ | | `/api/stats` | Authorization 추가됨 | JWT 검증 ✅ (2025-08-28 해결) | --- ## 3. 취약점 상세 ### 3.1 이중 인증 체계 문제 ```python # rb8001 - 웹 요청 (/api/message) @app.post("/api/message") async def message(auth: str = Depends(verify_jwt_token)): user_uuid, username = auth # JWT에서 UUID 추출 # rb8001 - Slack 요청 (/api/slack/events) @app.post("/api/slack/events") async def slack_events(request: Request): slack_user_id = data.get("user") # JWT 없이 Slack ID 사용 ``` ### 3.2 skill-email - 서비스 간 통신 문제 ```python # rb8001에서 skill-email 호출 시 # 헤더 없이 호출 (Authorization, X-User-Id 모두 없음) await http_client.post( "http://skill-email:8501/api/email", json={"user_id": user_id} # 파라미터로만 전달 ) ``` ### 3.3 ~~Gateway - 일부 엔드포인트 JWT 검증 누락~~ ✅ 해결됨 (2025-08-28) ```python # /api/stats 엔드포인트 (main.py Line 285) # 수정 전: x_user_id: Optional[str] = Header(None) # 수정 후: user_id: str = Depends(get_verified_user) ✅ # 2025-08-28: JWT 검증 추가 완료 ``` --- ## 4. 공격 시나리오 ### 시나리오 1: Slack 경로 인증 우회 ```bash # Slack 이벤트로 위장하여 직접 호출 curl -X POST http://192.168.219.52:8001/api/slack/events \ -H "Content-Type: application/json" \ -d '{"user": "타겟_slack_id", "text": "명령어"}' # → JWT 없이 명령 실행 가능 ``` ### 시나리오 2: X-User-Id 헤더 조작 ```bash # rb10508_micro로 직접 호출 curl http://192.168.219.52:10508/api/chat \ -H "X-User-Id: 타겟_UUID" # → JWT 없이 X-User-Id만으로 인증 # Gateway /api/stats 호출 curl http://gateway:8100/api/stats/rb8001 \ -H "X-User-Id: 임의UUID" # → JWT 검증 없이 통계 조회 ``` --- ## 5. 해결 방안: Slack 권한 아이템화 ### 핵심 개념 - Slack을 Gmail처럼 권한 아이템으로 관리 - 웹에서 Slack OAuth 연결 시작 - slack_tokens 테이블로 매핑 관리 ### 구현 단계 #### 1. slack_tokens 테이블 생성 ```sql CREATE TABLE slack_tokens ( user_id UUID NOT NULL, slack_user_id VARCHAR(100), slack_team_id VARCHAR(100), access_token TEXT, is_equipped BOOLEAN DEFAULT false, equipped_to VARCHAR(50) ); ``` #### 2. Slack OAuth 플로우 - 웹 로그인 → Slack 연결 버튼 - Slack OAuth → 토큰 저장 - 아이템 획듍 → 장착 #### 3. Slack 이벤트 처리 - slack_user_id로 slack_tokens 조회 - user_id(UUID) 획듍 - 모든 처리 UUID로 통일 #### 4. 기존 개선사항 - Gateway /api/stats JWT 검증 추가 - X-User-Id 직접 신뢰 제거 --- ## 6. 영향도 평가 | 영역 | 영향도 | 설명 | |-----|-------|------| | **보안** | 🔴 높음 | X-User-Id 헤더 조작으로 인증 우회 가능 | | **데이터** | 🔴 높음 | 타인 데이터 접근 가능 (조회 위주) | | **서비스** | 🟡 중간 | 일부 서비스만 영향 | | **사용자** | 🔴 높음 | 개인정보 유출 위험 | --- ## 7. 구현 우선순위 | 우선순위 | 작업 | 담당 | 상태 | |---------|-----|------|------| | 1 | ~~Gateway /api/stats JWT 검증 추가~~ | ~~로컬 개발자~~ | ✅ 완료 (2025-08-28) | | 2 | ~~rb8001 UUID5 → 51123 매핑 API~~ | ~~로컬 개발자~~ | ✅ 완료 (2025-08-28) | | 3 | ~~skill-email JWT 키 설정~~ | ~~51124 관리자~~ | ✅ 완료 (2025-08-28) | | 4 | ~~서비스 간 Bearer 인증~~ | ~~로컬 개발자~~ | ✅ 완료 (2025-08-28) | | 5 | Slack OAuth Frontend 연동 | 로컬 개발자 | 향후 | --- ## 8. 검증 방법 ### 8.1 보안 테스트 ```bash # JWT 없이 접근 시도 - 실패해야 함 curl -X GET http://gateway:8100/api/stats/rb8001 \ -H "X-User-Id: fake-uuid" # Expected: 401 Unauthorized # 유효한 JWT로 접근 - 성공해야 함 curl -X GET http://gateway:8100/api/stats/rb8001 \ -H "Authorization: Bearer $JWT_TOKEN" # Expected: 200 OK ``` ### 8.2 서비스별 검증 - Gateway /api/stats: JWT 없이 접근 → 401 - rb8001 /api/slack/events: Slack 서명 검증 확인 - rb10508_micro: JWT 또는 대체 인증 구현 확인 - skill-email: 서비스 간 인증 방식 확인 --- ## 9. 관련 문서 - [UUID vs username 혼용 문제](./250827_UUID_username_혼용_CRITICAL.md) - [JWT 인증 구현](./250827_JWT_인증_구현_COMPLETED.md) - [시스템 아키텍처](../300_architecture/310_전체_시스템_구조_컨테이너와_마이크로서비스.md) --- ## 10. 결론 **Slack 권한 아이템화로 통합 인증 체계 구축** 해결 방안: 1. **Slack을 아이템으로**: Gmail과 동일한 UX 2. **웹 UUID 중심**: 모든 채널 UUID로 통합 3. **매핑 테이블**: slack_tokens로 관리 4. **기억 통합**: 모든 대화 하나의 사용자로 관리 모든 서비스에 JWT 인증을 구현하고, Gateway에서 일관된 검증을 수행해야 합니다. --- *최종 수정: 2025-08-28 10:00* *수정 내용: Gateway /api/stats JWT 검증 추가 완료* *확인: 401 Unauthorized 정상 반환 확인*