diff --git a/troubleshooting/250827_JWT_인증_완전_미구현_CRITICAL.md b/troubleshooting/250827_JWT_인증_완전_미구현_CRITICAL.md index e7cb8ea..7510a6d 100644 --- a/troubleshooting/250827_JWT_인증_완전_미구현_CRITICAL.md +++ b/troubleshooting/250827_JWT_인증_완전_미구현_CRITICAL.md @@ -22,28 +22,32 @@ --- -## 2. 취약점 상세 분석 +## 2. 취약점 상세 분석 (실제 확인 결과) -### 2.1 auth-server (51123) +### 2.1 auth-server (51123) - 부분 구현 ```python # /home/admin/auth-server/app/core/auth.py -# ✅ JWT 생성/검증 코드는 존재 -JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your-secret-key-change-this") +# ✅ JWT 생성/검증 코드 구현됨 +JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY") # 실제: 9cc562b629... -def create_access_token(data: Dict[str, Any]) -> str: - # JWT 토큰 생성 로직 구현됨 - -def decode_access_token(token: str) -> Dict[str, Any]: - # JWT 토큰 검증 로직 구현됨 +# /home/admin/auth-server/app/providers/gmail.py:208 +jwt_token = create_access_token(data={ + "sub": username, + "email": user_email, + "name": user_name +}) ``` -**문제점**: -- JWT 발급 코드는 있지만 실제 사용되지 않음 -- 각 서비스가 이 토큰을 검증하지 않음 +**현재 상태**: +- ✅ JWT 토큰 발급 구현됨 (Gmail OAuth 후) +- ✅ JWT_SECRET_KEY 설정됨: `9cc562b629...` +- ❌ 하지만 백엔드 서비스들이 이 토큰을 검증하지 않음 -### 2.2 robeing-gateway (51123:8100) +### 2.2 robeing-gateway (51123:8100) - 부분 구현 ```python # /home/admin/robeing-gateway/app/main.py:40-65 +JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY") # 실제: 9cc562b629... (auth-server와 동일) + def get_verified_user(authorization: Optional[str] = Header(None)): if not authorization or not authorization.startswith("Bearer "): return "default" # 🔴 JWT 없어도 통과! @@ -57,13 +61,17 @@ def get_verified_user(authorization: Optional[str] = Header(None)): return "default" # 🔴 잘못된 JWT도 통과! ``` -**문제점**: -- JWT 검증 실패 시 에러 반환이 아닌 "default" 사용자로 처리 -- 인증 우회 가능 +**현재 상태**: +- ✅ JWT_SECRET_KEY 설정됨 (auth-server와 동일한 키) +- ⚠️ JWT 검증 로직은 있지만 실패 시 "default"로 폴백 +- ❌ 인증 실패를 에러로 처리하지 않음 -### 2.3 rb8001 (51124:8001) +### 2.3 rb8001 (51124:8001) - 완전 미구현 ```python # /home/admin/ivada_project/rb8001/main.py:51-70 +# ❌ JWT_SECRET_KEY 미설정 (.env에 기본값 그대로) +JWT_SECRET_KEY = "your-jwt-secret-key" # 🔴 51123과 다른 키! + @app.post("/api/message") async def message_endpoint(request: MessageRequest, req: Request): # X-User-Id 헤더에서 사용자 ID 가져오기 @@ -73,12 +81,22 @@ async def message_endpoint(request: MessageRequest, req: Request): if not user_id: user_id = "web_user" # 🔴 기본값 사용! + + # JWT 검증 코드 전혀 없음! ``` -**문제점**: -- JWT 검증 코드 전혀 없음 -- X-User-Id 헤더만 확인 (조작 가능) -- python-jose 라이브러리 미설치 +**실제 확인 결과**: +- ✅ python-jose 라이브러리는 설치됨 (requirements.txt:39) +- ❌ JWT_SECRET_KEY 설정 안됨 (기본값 그대로) +- ❌ JWT 검증 코드 전혀 없음 +- ❌ Authorization 헤더 처리 없음 (cron용 토큰만 있음) +- ❌ X-User-Id 헤더만 신뢰 (보안 취약) + +### 2.4 Frontend (로컬) - 완전 미구현 +**실제 확인 결과**: +- ❌ Authorization Bearer 토큰 전송 안 함 +- ❌ localStorage의 'token' 사용 안 함 +- ❌ API 호출 시 JWT 헤더 없음 --- @@ -181,26 +199,32 @@ curl -X POST http://localhost:8100/api/chat \ --- -## 5. 근본 원인 분석 +## 5. 근본 원인 분석 (실제 확인 기반) -### 5.1 설계 단계 문제 -- JWT 인증 시스템 설계는 되었으나 구현 미완료 -- 개발 편의를 위한 임시 우회 코드가 프로덕션에 배포 +### 5.1 부분적 구현 상태 +| 컴포넌트 | JWT 발급 | JWT 검증 | SECRET_KEY | 실제 사용 | +|---------|---------|---------|-----------|----------| +| auth-server (51123) | ✅ 구현 | ✅ 구현 | ✅ 설정됨 | ✅ OAuth 후 발급 | +| robeing-gateway (51123) | - | ⚠️ 부분 | ✅ 설정됨 | ❌ 실패 시 default | +| rb8001 (51124) | - | ❌ 없음 | ❌ 기본값 | ❌ 사용 안함 | +| Frontend | - | - | - | ❌ 헤더 안보냄 | ### 5.2 구현 단계 문제 -- 각 마이크로서비스별 JWT 검증 미들웨어 미구현 -- python-jose 등 필요 라이브러리 미설치 -- 환경변수 JWT_SECRET_KEY 미설정 또는 불일치 +- **51123**: JWT 인프라는 준비되었으나 엄격한 검증 미적용 +- **51124**: JWT 검증 코드 완전 미구현 (라이브러리만 설치) +- **Frontend**: Authorization 헤더 전송 로직 미구현 +- **환경변수**: 51123과 51124의 JWT_SECRET_KEY 불일치 -### 5.3 테스트 단계 문제 -- 보안 테스트 부재 -- JWT 검증 관련 단위 테스트 없음 -- 통합 테스트에서 인증 검증 누락 +### 5.3 통합 문제 +- auth-server는 JWT 발급하지만 아무도 검증하지 않음 +- Gateway는 검증 실패해도 "default"로 처리 +- rb8001은 X-User-Id 헤더만 신뢰 +- Frontend는 토큰을 받지만 사용하지 않음 -### 5.4 배포 단계 문제 -- 보안 체크리스트 미적용 -- 코드 리뷰에서 보안 검증 누락 -- 프로덕션 배포 전 보안 감사 미실시 +### 5.4 보안 의식 부재 +- 개발 편의를 위한 우회 코드가 프로덕션에 배포 +- JWT 검증 없이도 서비스가 동작하도록 설계 +- 보안 테스트 및 감사 프로세스 부재 --- @@ -208,14 +232,15 @@ curl -X POST http://localhost:8100/api/chat \ ### 6.1 긴급 조치 (D-Day) -#### Step 1: JWT_SECRET_KEY 생성 및 배포 +#### Step 1: JWT_SECRET_KEY 통일 (51123의 기존 키 사용) ```bash -# 51123 서버에서 실행 -openssl rand -base64 32 -# 결과: XKj8n2bL9Qa1pRt5vY6wC3dF7gH0iM4sN8oP2qU5xZ= +# 51123 서버는 이미 설정됨: 9cc562b629... +# 51124 서버의 모든 서비스 .env 파일 수정 필요: -# 모든 서비스의 .env 파일에 추가 -JWT_SECRET_KEY=XKj8n2bL9Qa1pRt5vY6wC3dF7gH0iM4sN8oP2qU5xZ= +# rb8001/.env 수정 +JWT_SECRET_KEY=9cc562b6296b87b02dd89045a2e7e11c249713a59a5ac0160d852121f1289664 + +# 다른 서비스들도 동일하게 설정 ``` #### Step 2: 각 서비스에 JWT 검증 미들웨어 추가 @@ -296,21 +321,26 @@ def get_verified_user(authorization: Optional[str] = Header(None)): ### 6.2 단기 조치 (D+1 ~ D+3) -1. **의존성 설치** -```bash -# 각 서비스 디렉토리에서 -pip install python-jose[cryptography] -# requirements.txt 업데이트 +1. **Frontend 수정 (로컬 개발자)** +```javascript +// API 호출 시 Authorization 헤더 추가 +const token = localStorage.getItem('token'); +headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' +} ``` -2. **환경변수 통일** -- 모든 서비스의 .env 파일에 동일한 JWT_SECRET_KEY 설정 -- Docker Compose 환경변수 업데이트 +2. **Gateway 수정 (51123)** +```python +# "default" 반환 대신 401 에러 발생 +if not authorization: + raise HTTPException(401, "Authorization required") +``` -3. **테스트 구현** -- JWT 검증 단위 테스트 -- 인증 실패 시나리오 테스트 -- 통합 테스트 업데이트 +3. **환경변수 통일 확인** +- 51124의 모든 서비스가 51123과 동일한 JWT_SECRET_KEY 사용 +- Docker Compose 환경변수 동기화 ### 6.3 중장기 조치 (D+7 ~ D+30) @@ -414,14 +444,24 @@ curl -X POST http://192.168.219.52:8001/api/message \ ## 11. 결론 -**현재 시스템은 인증이 완전히 무력화된 극도로 위험한 상태입니다.** +**현재 시스템은 JWT 인증이 부분적으로만 구현되어 완전히 무력화된 상태입니다.** -이는 단순한 버그가 아닌 시스템 전체의 보안을 위협하는 Critical 취약점으로, 즉시 모든 개발을 중단하고 이 문제 해결에 집중해야 합니다. +### 실제 확인 결과 요약: +- **51123**: JWT 발급은 되지만 검증 실패 시 우회 허용 +- **51124**: JWT 검증 코드 완전 미구현, 잘못된 SECRET_KEY +- **Frontend**: Authorization 헤더 전송 안 함 -JWT 검증 구현은 선택이 아닌 필수이며, 이를 통해서만 사용자 데이터 보호와 시스템 무결성을 보장할 수 있습니다. +이는 단순한 구현 누락이 아닌 시스템 전체의 보안을 위협하는 Critical 취약점으로, 즉시 모든 개발을 중단하고 이 문제 해결에 집중해야 합니다. + +### 우선순위: +1. **즉시**: 51124 서버 JWT_SECRET_KEY 통일 +2. **D+1**: rb8001 JWT 검증 구현 +3. **D+2**: Frontend Authorization 헤더 추가 +4. **D+3**: Gateway 엄격한 검증 적용 --- *작성 완료: 2025-08-27 14:30* +*수정 완료: 2025-08-27 15:00 (실제 확인 결과 반영)* *최종 검토: 51123 서버 관리자* *다음 업데이트: 조치 시작 후 즉시* \ No newline at end of file