보안포털 코드 보안 강화 — 7가지 취약점 수정기
FastAPI로 구축한 내부 보안 관리 포털을 운영하면서 코드 리뷰를 진행했습니다.
정보보안 전문가 입장에서 직접 취약점을 찾고 수정한 과정을 공유합니다.
초보 개발자도 이해할 수 있도록 쉽게 설명했어요.
정보보안 전문가 입장에서 직접 취약점을 찾고 수정한 과정을 공유합니다.
초보 개발자도 이해할 수 있도록 쉽게 설명했어요.
📋 발견된 취약점 목록
코드 리뷰 결과 총 7가지 문제를 발견했습니다.
| 번호 | 항목 | 심각도 |
|---|---|---|
| 1 | CORS 전체 개방 | 🔴 심각 |
| 2 | JWT 토큰 만료시간 8시간 | 🔴 심각 |
| 3 | JWT 서명키 fallback 설정 | 🔴 심각 |
| 4 | DB 연결 풀 미설정 | 🟡 주의 |
| 5 | DB 오류 시 rollback 없음 | 🟡 주의 |
| 6 | deprecated API 사용 | 🟡 주의 |
| 7 | 테스트 fixture 중복 가능성 | 🟡 주의 |
1️⃣ CORS 전체 개방 (🔴 심각)
CORS가 뭔가요?
브라우저가 다른 도메인의 API 호출을 제어하는 보안 정책이에요. allow_origins=["*"]로 설정하면 어떤 웹사이트에서든 우리 API를 호출할 수 있습니다.
# 수정 전 (위험)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 모든 도메인 허용
allow_methods=["*"],
allow_headers=["*"],
)
# 수정 후 (안전)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://[서버주소]"], # 특정 도메인만 허용
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["Authorization", "Content-Type"],
)
💡 쉽게 말하면: 현관문을 아무나 열 수 있게 뒀다가, 우리 가족만 열 수 있도록 잠금장치를 설치한 것.
⚠️ 주의: CORS는 IP 접속 차단이 아닙니다. 브라우저 단에서 동작하므로 사용자의 직접 접속에는 영향을 주지 않아요.
2️⃣ JWT 토큰 만료시간 8시간 (🔴 심각)
JWT 토큰은 로그인 후 발급되는 출입증이에요. 만료시간이 길수록 토큰이 탈취됐을 때 피해가 커집니다.
# 수정 전 (위험)
ACCESS_TOKEN_EXPIRE_MINUTES = 480 # 8시간
# 수정 후 (안전)
ACCESS_TOKEN_EXPIRE_MINUTES = 30 # 30분
💡 쉽게 말하면: 회사 출입증 유효기간을 8시간에서 30분으로 단축. 출입증이 도난당해도 30분 후엔 자동 만료됩니다.
💡 보안 포털, 금융, 의료 시스템은 15~30분이 업계 표준입니다.
3️⃣ JWT 서명키 fallback 설정 (🔴 심각)
환경변수가 없을 때 기본값으로 동작하는 코드는 매우 위험합니다. 누구나 알 수 있는 키로 토큰을 위조할 수 있어요.
# 수정 전 (위험)
SECRET_KEY = os.getenv('SECRET_KEY', 'fallback-key')
# .env 파일 없으면 'fallback-key'로 JWT 서명
# 누구나 이 키로 토큰 위조 가능
# 수정 후 (안전)
SECRET_KEY = os.getenv('SECRET_KEY')
if not SECRET_KEY:
raise RuntimeError('SECRET_KEY 환경변수가 설정되지 않았습니다')
# 키 없으면 서버 자체가 실행되지 않음
🚨 쉽게 말하면: 마스터키를 잃어버리면 만능키로 열리게 해뒀다가, 마스터키 없으면 문 자체가 잠기도록 변경.
4️⃣ DB 연결 풀 미설정 (🟡 주의)
DB 연결 풀이란 미리 연결을 여러 개 만들어두고 재사용하는 방식이에요. 설정이 없으면 동시 접속자가 많을 때 DB 연결이 부족해질 수 있습니다.
# 수정 전
engine = create_engine(DATABASE_URL)
# 기본값 사용 → 동시 접속자 많으면 DB 연결 부족
# 수정 후
engine = create_engine(
DATABASE_URL,
pool_size=10, # 기본 연결 수
max_overflow=20, # 최대 추가 연결
pool_timeout=30, # 연결 대기 최대 시간(초)
pool_recycle=1800, # 30분마다 연결 갱신
)
💡 쉽게 말하면: 은행 창구를 기본 10개 열어두고, 사람이 몰리면 최대 20개까지 추가로 여는 방식.
5️⃣ DB 오류 시 rollback 없음 (🟡 주의)
DB 작업 중 오류가 나면 반드시 작업을 취소(rollback)해야 데이터가 꼬이지 않아요.
# 수정 전
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close() # 오류 발생해도 그냥 닫음
# 수정 후
def get_db():
db = SessionLocal()
try:
yield db
except Exception:
db.rollback() # 오류 시 작업 먼저 취소
raise
finally:
db.close() # 그 다음 닫음
💡 쉽게 말하면: 은행 거래 중 오류나면 그냥 창구를 닫았다가, 이제는 거래를 먼저 취소한 후 창구를 닫도록 변경. 데이터 꼬임 방지.
6️⃣ deprecated API 사용 (🟡 주의)
Python 3.12부터 datetime.utcnow()는 deprecated(구식)로 경고가 발생합니다.
# 수정 전 (경고 발생)
from datetime import datetime, timedelta
expire = datetime.utcnow() + timedelta(...)
# 수정 후 (최신 표준)
from datetime import datetime, timedelta, timezone
expire = datetime.now(timezone.utc) + timedelta(...)
💡 쉽게 말하면: 구형 시계를 신형 시계로 교체. 기능은 같지만 최신 표준을 따릅니다.
7️⃣ 테스트 fixture 중복 문제 (🟡 주의)
테스트를 반복 실행할 때 같은 사용자명으로 DB에 insert하면 중복 오류가 발생할 수 있어요.
# 수정 전 (중복 오류 가능)
user = User(
username="testuser", # 항상 같은 이름 → 중복 오류
email="test@company.com"
)
# 수정 후 (중복 방지)
import uuid
unique = uuid.uuid4().hex[:8] # 랜덤 8자리 생성
user = User(
username=f"testuser_{unique}", # testuser_a3f9b2c1
email=f"test_{unique}@company.com" # 매번 고유한 이메일
)
💡 쉽게 말하면: 테스트할 때마다 같은 이름의 직원을 등록하려다 오류나던 것을, 매번 다른 사번으로 등록하도록 변경.
✅ 수정 결과
7개 취약점 수정 후 기존 테스트 12개 전부 통과를 확인했습니다.
$ pytest tests/ --no-cov
............
======================== 12 passed, 4 warnings ========================
............
======================== 12 passed, 4 warnings ========================
🏗️ 현재 VM 아키텍처
외부 인터넷
↓
Nginx (80/443포트) ← 관문 역할
├── 보안포털 → FastAPI (uvicorn, 내부 포트)
└── 다른서비스 → Docker 컨테이너 (격리됨)
내부망
├── FastAPI (uvicorn) ← 보안포털 백엔드
└── PostgreSQL (내부만) ← 외부 직접 접근 불가
💡 보안 포인트: PostgreSQL은 외부에서 직접 접근 불가능합니다. 내부에서만 접근할 수 있어요.
🐳 다음 계획 — Docker 전환
현재 FastAPI가 systemd로 직접 실행되고 있는데, 보안 강화를 위해 Docker 컨테이너로 전환할 예정입니다.
| 현재 구성 | 도커 전환 후 |
|---|---|
| systemd로 FastAPI 직접 실행 | 컨테이너 A (FastAPI) |
| 직접 설치된 PostgreSQL | 컨테이너 B (PostgreSQL) |
| 직접 설치된 Nginx | 컨테이너 C (Nginx) |
| 도커 전환 기대 효과 | 설명 |
|---|---|
| 프로세스 격리 | 하나가 뚫려도 다른 서비스 안전 |
| 네트워크 격리 | 컨테이너 간 통신만 허용 |
| 버전 관리 | 이미지로 롤백 용이 |
| 배포 자동화 | docker-compose로 한 번에 관리 |
🚀 다음 포스팅에서 Docker 전환 과정을 상세히 공유할 예정입니다!
📝 마치며
코드 리뷰는 개발 후 선택이 아니라 필수입니다. 특히 보안 시스템이라면 더욱 그렇죠.
오늘 수정한 7가지 중 🔴 심각 3개는 실제 운영 중인 시스템에서 흔히 발견되는 취약점입니다. 여러분의 코드도 한 번 점검해보세요!
'01. AI 테크 & 트렌드 (Main) > Claude & Anthropic' 카테고리의 다른 글
| [보안포털 구축기 5편] 정보자산 관리전면 고도화 (1) | 2026.05.01 |
|---|---|
| [보안포털 구축기 4편]도메인 연동 &보안이슈관리 고도화 (0) | 2026.04.27 |
| [보안포털 구축기 3편] systemd → Docker 전환 — 기존 데이터 무손실 이전 (1) | 2026.04.18 |
| [보안포털 구축기 1편]보안포털 테스트 하네스 구축기 — CI/CD 자동화 완성 (0) | 2026.04.17 |
| Claude에서 Harness란 무엇인가? (0) | 2026.04.17 |