NestJS API 보안 이슈 분석 - 문제점과 해결책
by 김지운
들어가며
최근 여러 서버 및 API 등에서 보안 사고가 발생하고 있다. 이중 공공 기관등의 서버 직접 침해는 제외하고 API 관련 내용에 대해서 어떤 문제가 있고 왜 발생하고 해결책에 대해 고민해본다.
API 보안은 현대 웹 애플리케이션에서 가장 중요한 고려사항 중 하나이다. 특히 NestJS와 같은 엔터프라이즈급 프레임워크를 사용할 때는 보안에 대한 체계적인 접근이 필요하다.
주요 API 보안 문제점
1. 인증 및 인가 취약점
가장 흔한 문제 중 하나는 인증(Authentication)과 인가(Authorization)의 부적절한 구현이다.
문제점:
- JWT 토큰의 만료 시간이 너무 길거나 검증이 제대로 이루어지지 않음
- 역할 기반 접근 제어(RBAC)가 제대로 구현되지 않음
- 세션 관리가 취약함
발생 원인:
- 개발 초기 단계에서 보안을 간과하고 기능 구현에만 집중
- 보안 모범 사례에 대한 이해 부족
- 테스트 환경과 프로덕션 환경의 보안 설정 차이
2. 입력 검증 부재
사용자 입력에 대한 검증이 제대로 이루어지지 않으면 다양한 공격에 취약해진다.
문제점:
- SQL Injection
- NoSQL Injection
- Command Injection
- XSS (Cross-Site Scripting)
- XXE (XML External Entity) 공격
발생 원인:
- DTO(Data Transfer Object) 검증 로직 누락
- 화이트리스트 기반 검증 대신 블랙리스트 사용
- 파일 업로드 시 확장자 및 크기 검증 부재
3. 과도한 정보 노출
에러 메시지나 응답에서 민감한 정보가 노출되는 경우가 많다.
문제점:
- 스택 트레이스가 그대로 노출됨
- 데이터베이스 스키마 정보 노출
- 내부 시스템 구조 정보 노출
- API 버전 정보 등 메타데이터 과다 노출
발생 원인:
- 개발 편의성을 위해 상세한 에러 메시지 사용
- 프로덕션 환경에서도 디버그 모드 활성화
- 에러 처리 미흡
4. Rate Limiting 부재
API 호출에 대한 제한이 없으면 DDoS 공격이나 무차별 대입 공격에 취약하다.
문제점:
- 무제한 API 호출 가능
- 로그인 시도 횟수 제한 없음
- 특정 IP나 사용자에 대한 제한 없음
발생 원인:
- Rate limiting의 중요성 인식 부족
- 구현 복잡도에 대한 우려
- 성능 영향에 대한 과도한 걱정
5. CORS 설정 오류
Cross-Origin Resource Sharing 설정이 잘못되면 CSRF 공격에 취약해진다.
문제점:
- 모든 Origin 허용 (
*) - Credentials 허용과 함께 와일드카드 사용
- 필요한 헤더나 메서드만 허용하지 않음
발생 원인:
- CORS 정책에 대한 이해 부족
- 개발 편의성을 위해 느슨한 설정 사용
- 프로덕션 환경에서도 개발 환경 설정 유지
6. 민감한 데이터 평문 저장
비밀번호나 개인정보를 암호화하지 않고 저장하는 경우가 있다.
문제점:
- 비밀번호 평문 저장
- 개인정보 암호화 미흡
- API 키나 토큰을 코드에 하드코딩
발생 원인:
- 암호화의 필요성 인식 부족
- 구현 복잡도 회피
- 환경 변수 관리 미흡
보안 문제점에 대한 대응의 현실판
핵심 요약
- 기술적으로 “무엇이 문제인지”는 대부분 알고 있다. 문제는 “언제, 어떻게 고칠지”에 대한 조직적 의사결정과 리스크 수용이다.
- 취약점 식별은 쉽다. 개선(마이그레이션, 다운타임 설득, 회귀 테스트)과 책임소재가 어려운 지점이다.
확인은 쉽다, 개선이 어렵다
npm audit, IDE 취약점 스캐너(mend.io 등)로 이슈 추적은 즉시 가능# npm audit를 통한 취약점 점검 npm audit npm audit fix- 어려운 점
- 연쇄적 버전 업그레이드(의존 모듈 동반 상향, 브레이킹 체인지)
- 테스트 커버리지 부족으로 인한 회귀 리스크
- 다운타임/릴리스 윈도우 허용을 얻기 위한 내부 설득
현장에서 자주 보이는 안티패턴
- 인증/인가를 “임시로” 느슨하게 풀고 그대로 굳어짐
- 목적이 다른 API를 권한 범위만 비틀어 재사용
- 내부 백오피스용 우회키를 제품 경로에 유입
- 공개/비공개 도메인을 분리하지 않고 한 API에 혼합
- 응답 필터링/프로젝션 정책(PROFILE_SELECT_OPTION 등)이 누적 변경으로 무너짐
실패가 생기는 전형적 흐름(예)
1) 원래 분리했어야 할 /users/profiles/public와 /users/profiles/private를 개발속도/복잡도 이유로 합침
2) 이후 기능 추가(예: 팔로워 수) 시 응답 필터 누락
3) 쿼리 프로젝션 옵션에 민감정보가 섞여 들어오고, 일부 엔드포인트에서 필터링 누락
4) “안전한 내부 호출만”이라는 가정이 깨지는 순간 사고로 이어짐
실무적 대안 체크리스트
- API 스코프를 공개/비공개로 물리적으로 분리하고, 합칠 때는 응답 빌더에서 화이트리스트 필터를 기본값으로 사용
- 역할·권한은 느슨화 대신 “명시적 추가 엔드포인트”로 대응(임시 완화 금지)
- 프로덕션에 들어가는 우회키/백도어성 파라미터는 금지, 필요 시 별도 네트워크 경계 내 내부 전용 서비스로 격리
- 주기적 의존성 업그레이드 데이 운영(브레이킹 체인지 적립 방지)
- 변경 전후 API 스냅샷/계약 테스트로 회귀 리스크 통제
마무리
한 줄 핵심
- 보안은 “지속 업그레이드 + 명시적 분리 + 테스트로 통제”가 전부다.
바로 적용 가능한 액션 아이템
- 의존성 정기 업그레이드 스프린트 운영(브레이킹 체인지 적립 금지)
- OS/런타임은 메이저 릴리스 라인 추종(보안 패치 라인 유지)
- 공개/비공개/민감 데이터 접근 경로를 물리적으로 분리
- 화이트리스트 기반 응답 필터를 기본 정책으로 채택
- 계약/스냅샷/보안 회귀 테스트를 CI에 상시화
- 완화(waiver)는 만료일·보상통제와 함께 티켓으로 관리
마지막으로
- 모든 노력을 다해도 사고는 완전히 0이 되지 않는다. 중요한 건 “빨리 감지하고, 영향 범위를 작게, 복구를 빠르게” 하는 체계다.
- AI 도구로 문서·테스트 생산성은 좋아지고 있지만, 공격자도 똑같이 빨라진다. 기본기에 충실하되, 자동화로 빈도를 높이자.
- 오늘도 우리의 서버가 안전하길.
참고 자료
Subscribe via RSS