docs: JWT 보안 취약점 문서 전면 재작성 - 확인된 사실 기반

- 이중 인증 체계 문제 명확화 (웹: JWT/UUID vs Slack: Slack ID)
- rb8001 /api/slack/events JWT 없이 작동 확인
- Frontend API 호출 패턴 실제 확인 내용 반영
- 서비스 간 통신 인증 부재 문제 추가
- 추측 제거, 실제 코드 분석 기반 작성
This commit is contained in:
happybell80 2025-08-27 17:27:48 +09:00
parent 2ece715b1f
commit c0f345e4c4

View File

@ -11,10 +11,11 @@
## 1. 문제 요약 ## 1. 문제 요약
### 🚨 핵심 문제 ### 🚨 핵심 문제
**51124 서버의 대부분 서비스가 JWT 인증 없이 작동** **이중 인증 체계로 인한 보안 취약점**
- X-User-Id 헤더만 신뢰하는 서비스 존재 - **웹 경로**: JWT + UUID 사용 (rb8001 /api/message)
- 파라미터로 받은 user_id를 검증 없이 사용 - **Slack 경로**: JWT 없이 Slack ID 사용 (rb8001 /api/slack/events)
- Gateway의 일부 엔드포인트가 JWT 검증 누락 - **서비스 간 통신**: 통일된 인증 체계 없음
- **Gateway**: /api/stats 엔드포인트 JWT 검증 누락
### 보안 영향 ### 보안 영향
- **인증 우회**: 헤더 조작으로 다른 사용자 행세 가능 - **인증 우회**: 헤더 조작으로 다른 사용자 행세 가능
@ -27,67 +28,83 @@
### 2.1 JWT 인증 구현 상태 ### 2.1 JWT 인증 구현 상태
| 서비스 | JWT 인증 | user_id 처리 | Authorization 헤더 | 위험도 | | 서비스/엔드포인트 | JWT 인증 | user_id 처리 | 현재 상태 |
|--------|---------|--------------|-------------------|--------| |-------------------|---------|--------------|----------|
| **rb8001** | ✅ 구현 | UUID (JWT sub) + username | ✅ Bearer 토큰 | 안전 | | **rb8001 /api/message** | ✅ 구현 | UUID (JWT sub) | 정상 |
| **rb10508_micro** | ❌ 없음 | X-User-Id 헤더만 | ❌ 없음 | 🔴 위험 | | **rb8001 /api/slack/events** | ❌ 없음 | Slack ID 직접 사용 | Slack 전용 |
| **skill-email** | ❌ 없음 | 파라미터 "test" | ❌ 없음 | 🔴 위험 | | **rb8001 /complete** | ❌ 없음 | "external_service" 고정 | 내부 API |
| **skill-news** | ❌ 없음 | 미구현 | ❌ 없음 | 🟡 중간 | | **rb10508_micro** | ❌ 없음 | X-User-Id 헤더 신뢰 | 🔴 취약 |
| **robeing-monitor** | ❌ 없음 | 미구현 | ❌ 없음 | 🟡 중간 | | **skill-email** | ❌ 없음 | 파라미터 user_id | 🔴 취약 |
| **skill-news** | ❌ 없음 | 미사용 중 | - |
### 2.2 Gateway 라우팅 현황 ### 2.2 Frontend API 호출 패턴
| 엔드포인트 | JWT 검증 | Authorization 전달 | 문제점 | | 엔드포인트 | Frontend에서 보내는 헤더 | Gateway 검증 |
|-----------|---------|-------------------|--------| |--------------|------------------------|-------------|
| `/api/chat/*` | ✅ 검증 | ✅ 전달 | 정상 | | `/api/chat` | Authorization + X-User-Id | JWT 검증 ✅ |
| `/api/stats/*` | ❌ 없음 | ❌ 없음 | X-User-Id만 신뢰 | | `/api/history` | Authorization + X-User-Id | JWT 검증 ✅ |
| `/api/items/*` | ✅ 검증 | ❌ 없음 | 헤더 전달 누락 | | `/api/items/gmail` | Authorization + X-User-Id | JWT 검증 ✅ |
| `/api/stats` | X-User-Id만 | 검증 없음 ❌ |
--- ---
## 3. 취약점 상세 ## 3. 취약점 상세
### 3.1 rb10508_micro - 인증 우회 가능 ### 3.1 이중 인증 체계 문제
```python ```python
# 현재 상태 - 위험 # rb8001 - 웹 요청 (/api/message)
user_id = request.headers.get("X-User-Id") # 검증 없이 신뢰 @app.post("/api/message")
# 공격자가 X-User-Id: "다른사용자UUID" 설정 가능 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 - 하드코딩된 기본값 ### 3.2 skill-email - 서비스 간 통신 문제
```python ```python
# main.py Line 73 # rb8001에서 skill-email 호출 시
user_id: str = "test" # 하드코딩 # 헤더 없이 호출 (Authorization, X-User-Id 모두 없음)
# JWT 검증 전혀 없음 await http_client.post(
# 파라미터로 받은 user_id 그대로 사용 "http://skill-email:8501/api/email",
json={"user_id": user_id} # 파라미터로만 전달
)
``` ```
### 3.3 Gateway - 일관성 없는 검증 ### 3.3 Gateway - 일부 엔드포인트 JWT 검증 누락
```python ```python
# /api/stats 엔드포인트 # /api/stats 엔드포인트 (main.py Line 285)
x_user_id: Optional[str] = Header(None) # JWT 검증 없음 x_user_id: Optional[str] = Header(None) # JWT 검증 없음
# 누구나 접근 가능 # 인증 없이 X-User-Id 헤더만 사용
# /api/chat은 JWT 검증하지만 stats는 누락
``` ```
--- ---
## 4. 공격 시나리오 ## 4. 공격 시나리오
### 시나리오 1: 타인 이메일 접근 ### 시나리오 1: Slack 경로 인증 우회
```bash ```bash
# 공격자가 skill-email 직접 호출 # Slack 이벤트로 위장하여 직접 호출
curl -X POST http://192.168.219.52:8501/api/email \ curl -X POST http://192.168.219.52:8001/api/slack/events \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"user_id": "타겟사용자UUID"}' -d '{"user": "타겟_slack_id", "text": "명령어"}'
# → 타겟 사용자의 이메일 데이터 접근 # → JWT 없이 명령 실행 가능
``` ```
### 시나리오 2: 통계 조작 ### 시나리오 2: X-User-Id 헤더 조작
```bash ```bash
# 인증 없이 stats 접근 # 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 \ curl http://gateway:8100/api/stats/rb8001 \
-H "X-User-Id: 임의UUID" -H "X-User-Id: 임의UUID"
# → 다른 사용자의 통계 조회/조작 # → JWT 검증 없이 통계 조회
``` ```
--- ---
@ -96,34 +113,39 @@ curl http://gateway:8100/api/stats/rb8001 \
### 5.1 즉시 조치 (Phase 1) ### 5.1 즉시 조치 (Phase 1)
#### 모든 서비스 JWT 인증 추가 #### 1. Slack 경로 JWT 추가 또는 분리
```python ```python
# rb10508_micro, skill-email에 추가 필요 # 옵션 1: Slack 이벤트에도 JWT 요구
from app.auth import verify_jwt_token @app.post("/api/slack/events")
async def slack_events(
request: Request,
auth: Optional[str] = Depends(verify_jwt_optional)
):
if not auth:
# Slack 서명 검증로 대체
verify_slack_signature(request)
async def get_current_user(authorization: str = Header(...)): # 옵션 2: Slack과 웹을 완전 분리
if not authorization.startswith("Bearer "): # Slack 전용 서비스로 분리 고려
raise HTTPException(401, "Invalid authorization")
token = authorization.replace("Bearer ", "")
user_uuid, username = verify_jwt_token(token)
return user_uuid
``` ```
#### Gateway 모든 엔드포인트 JWT 검증 #### 2. Gateway /api/stats JWT 검증 추가
```python ```python
# main.py 수정 # Gateway main.py Line 283 수정
@app.get("/api/stats/{robeing_id}") @app.get("/api/stats/{robeing_id}")
async def get_stats( async def get_stats(
robeing_id: str, robeing_id: str,
x_user_id: str = Depends(get_verified_user) # JWT 검증 추가 x_user_id: str = Depends(get_verified_user) # JWT 검증 추가
): ):
# 현재는 x_user_id: Optional[str] = Header(None)로 취약
``` ```
### 5.2 중기 개선 (Phase 2) ### 5.2 중기 개선 (Phase 2)
1. **통합 인증 미들웨어** 1. **인증 체계 통합**
- 모든 서비스에 공통 JWT 검증 미들웨어 - Slack과 웹 경로 통합 또는 명확한 분리
- X-User-Id 헤더 완전 제거 - 모든 서비스에 일관된 인증 정책
- X-User-Id 헤더 직접 신뢰 제거
2. **서비스 간 통신 보안** 2. **서비스 간 통신 보안**
- 내부 API 키 또는 mTLS 적용 - 내부 API 키 또는 mTLS 적용
@ -139,8 +161,8 @@ async def get_stats(
| 영역 | 영향도 | 설명 | | 영역 | 영향도 | 설명 |
|-----|-------|------| |-----|-------|------|
| **보안** | 🔴 극심 | 인증 우회로 전체 시스템 침해 가능 | | **보안** | 🔴 높음 | X-User-Id 헤더 조작으로 인증 우회 가능 |
| **데이터** | 🔴 극심 | 타인 데이터 접근 및 조작 가능 | | **데이터** | 🔴 높음 | 타인 데이터 접근 가능 (조회 위주) |
| **서비스** | 🟡 중간 | 일부 서비스만 영향 | | **서비스** | 🟡 중간 | 일부 서비스만 영향 |
| **사용자** | 🔴 높음 | 개인정보 유출 위험 | | **사용자** | 🔴 높음 | 개인정보 유출 위험 |
@ -150,11 +172,11 @@ async def get_stats(
| 우선순위 | 작업 | 담당 | 예상 시간 | | 우선순위 | 작업 | 담당 | 예상 시간 |
|---------|-----|------|----------| |---------|-----|------|----------|
| 1 | skill-email JWT 인증 구현 | 로컬 개발자 | 2시간 | | 1 | Gateway /api/stats JWT 검증 추가 | 로컬 개발자 | 1시간 |
| 2 | rb10508_micro JWT 인증 구현 | 로컬 개발자 | 2시간 | | 2 | rb8001 Slack 경로 인증 강화 | 로컬 개발자 | 2시간 |
| 3 | Gateway /api/stats JWT 검증 추가 | 로컬 개발자 | 1시간 | | 3 | rb10508_micro JWT 구현 | 로컬 개발자 | 2시간 |
| 4 | X-User-Id 헤더 의존성 제거 | 로컬 개발자 | 3시간 | | 4 | skill-email 서비스 간 인증 | 로컬 개발자 | 3시간 |
| 5 | 통합 테스트 및 검증 | 51123 관리자 | 2시간 | | 5 | 통합 테스트 | 51123 관리자 | 2시간 |
--- ---
@ -174,9 +196,10 @@ curl -X GET http://gateway:8100/api/stats/rb8001 \
``` ```
### 8.2 서비스별 검증 ### 8.2 서비스별 검증
- rb10508_micro: JWT 없이 접근 → 401 - Gateway /api/stats: JWT 없이 접근 → 401
- skill-email: JWT 없이 접근 → 401 - rb8001 /api/slack/events: Slack 서명 검증 확인
- Gateway 모든 엔드포인트: JWT 검증 확인 - rb10508_micro: JWT 또는 대체 인증 구현 확인
- skill-email: 서비스 간 인증 방식 확인
--- ---
@ -190,13 +213,20 @@ curl -X GET http://gateway:8100/api/stats/rb8001 \
## 10. 결론 ## 10. 결론
**🔴 즉시 조치 필요 - 심각한 보안 취약점** **🔴 이중 인증 체계 문제 - 통합 필요**
현재 51124 서버의 대부분 서비스가 JWT 인증 없이 작동하여 인증 우회가 가능한 상태입니다. 확인된 주요 문제:
특히 skill-email과 rb10508_micro는 헤더 조작만으로 타인 데이터에 접근할 수 있어 즉시 수정이 필요합니다. 1. **웹 vs Slack**: JWT/UUID vs Slack ID 이중 체계
2. **Gateway**: /api/stats 엔드포인트 JWT 검증 누락
3. **서비스 간 통신**: 통일된 인증 없이 파라미터 신뢰
4. **rb10508_micro**: X-User-Id 헤더만 신뢰
모든 경로에 일관된 인증 체계를 구축하거나, Slack과 웹을 명확히 분리해야 합니다.
모든 서비스에 JWT 인증을 구현하고, Gateway에서 일관된 검증을 수행해야 합니다. 모든 서비스에 JWT 인증을 구현하고, Gateway에서 일관된 검증을 수행해야 합니다.
--- ---
*작성 완료: 2025-08-27 18:30* *최종 수정: 2025-08-27 19:30*
*수정 내용: 실제 확인된 사실 기반으로 전면 재작성*
*확인 경로: 51124 서버 조사, 로컬 코드 분석, Gateway 코드 검토*