DOCS/troubleshooting/250827_JWT_인증_보안_취약점_CRITICAL.md
happybell80 c0f345e4c4 docs: JWT 보안 취약점 문서 전면 재작성 - 확인된 사실 기반
- 이중 인증 체계 문제 명확화 (웹: JWT/UUID vs Slack: Slack ID)
- rb8001 /api/slack/events JWT 없이 작동 확인
- Frontend API 호출 패턴 실제 확인 내용 반영
- 서비스 간 통신 인증 부재 문제 추가
- 추측 제거, 실제 코드 분석 기반 작성
2025-08-27 17:27:48 +09:00

232 lines
7.2 KiB
Markdown

# JWT 인증 체계 보안 취약점 - CRITICAL
## 작성일: 2025-08-27
## 작성자: 51123 서버 관리자
## 상태: 🔴 CRITICAL - 인증 우회 가능한 보안 취약점 발견
## 영향 범위: 51124 전체 서비스 (rb10508_micro, skill-email, skill-news)
## 위험 수준: 매우 높음
---
## 1. 문제 요약
### 🚨 핵심 문제
**이중 인증 체계로 인한 보안 취약점**
- **웹 경로**: JWT + UUID 사용 (rb8001 /api/message)
- **Slack 경로**: JWT 없이 Slack ID 사용 (rb8001 /api/slack/events)
- **서비스 간 통신**: 통일된 인증 체계 없음
- **Gateway**: /api/stats 엔드포인트 JWT 검증 누락
### 보안 영향
- **인증 우회**: 헤더 조작으로 다른 사용자 행세 가능
- **데이터 접근**: 타인의 이메일, 통계 등 민감 정보 접근 가능
- **무결성 파괴**: 사용자 식별 체계 불일치로 데이터 오염
---
## 2. 서비스별 현황 분석
### 2.1 JWT 인증 구현 상태
| 서비스/엔드포인트 | JWT 인증 | user_id 처리 | 현재 상태 |
|-------------------|---------|--------------|----------|
| **rb8001 /api/message** | ✅ 구현 | UUID (JWT sub) | 정상 |
| **rb8001 /api/slack/events** | ❌ 없음 | Slack ID 직접 사용 | Slack 전용 |
| **rb8001 /complete** | ❌ 없음 | "external_service" 고정 | 내부 API |
| **rb10508_micro** | ❌ 없음 | X-User-Id 헤더 신뢰 | 🔴 취약 |
| **skill-email** | ❌ 없음 | 파라미터 user_id | 🔴 취약 |
| **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` | X-User-Id만 | 검증 없음 ❌ |
---
## 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 검증 누락
```python
# /api/stats 엔드포인트 (main.py Line 285)
x_user_id: Optional[str] = Header(None) # JWT 검증 없음
# 인증 없이 X-User-Id 헤더만 사용
# /api/chat은 JWT 검증하지만 stats는 누락
```
---
## 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. 해결 방안
### 5.1 즉시 조치 (Phase 1)
#### 1. Slack 경로 JWT 추가 또는 분리
```python
# 옵션 1: Slack 이벤트에도 JWT 요구
@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)
# 옵션 2: Slack과 웹을 완전 분리
# Slack 전용 서비스로 분리 고려
```
#### 2. Gateway /api/stats JWT 검증 추가
```python
# Gateway main.py Line 283 수정
@app.get("/api/stats/{robeing_id}")
async def get_stats(
robeing_id: str,
x_user_id: str = Depends(get_verified_user) # JWT 검증 추가
):
# 현재는 x_user_id: Optional[str] = Header(None)로 취약
```
### 5.2 중기 개선 (Phase 2)
1. **인증 체계 통합**
- Slack과 웹 경로 통합 또는 명확한 분리
- 모든 서비스에 일관된 인증 정책
- X-User-Id 헤더 직접 신뢰 제거
2. **서비스 간 통신 보안**
- 내부 API 키 또는 mTLS 적용
- 서비스 메시 아키텍처 검토
3. **감사 로깅**
- 모든 인증 시도 기록
- 실패한 접근 모니터링
---
## 6. 영향도 평가
| 영역 | 영향도 | 설명 |
|-----|-------|------|
| **보안** | 🔴 높음 | X-User-Id 헤더 조작으로 인증 우회 가능 |
| **데이터** | 🔴 높음 | 타인 데이터 접근 가능 (조회 위주) |
| **서비스** | 🟡 중간 | 일부 서비스만 영향 |
| **사용자** | 🔴 높음 | 개인정보 유출 위험 |
---
## 7. 구현 우선순위
| 우선순위 | 작업 | 담당 | 예상 시간 |
|---------|-----|------|----------|
| 1 | Gateway /api/stats JWT 검증 추가 | 로컬 개발자 | 1시간 |
| 2 | rb8001 Slack 경로 인증 강화 | 로컬 개발자 | 2시간 |
| 3 | rb10508_micro JWT 구현 | 로컬 개발자 | 2시간 |
| 4 | skill-email 서비스 간 인증 | 로컬 개발자 | 3시간 |
| 5 | 통합 테스트 | 51123 관리자 | 2시간 |
---
## 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. 결론
**🔴 이중 인증 체계 문제 - 통합 필요**
확인된 주요 문제:
1. **웹 vs Slack**: JWT/UUID vs Slack ID 이중 체계
2. **Gateway**: /api/stats 엔드포인트 JWT 검증 누락
3. **서비스 간 통신**: 통일된 인증 없이 파라미터 신뢰
4. **rb10508_micro**: X-User-Id 헤더만 신뢰
모든 경로에 일관된 인증 체계를 구축하거나, Slack과 웹을 명확히 분리해야 합니다.
모든 서비스에 JWT 인증을 구현하고, Gateway에서 일관된 검증을 수행해야 합니다.
---
*최종 수정: 2025-08-27 19:30*
*수정 내용: 실제 확인된 사실 기반으로 전면 재작성*
*확인 경로: 51124 서버 조사, 로컬 코드 분석, Gateway 코드 검토*