JWT(JSON Web Token)는 당사자 간 정보를 안전하게 JSON 객체로 전송하기 위한 컴팩트하고 독립적인 방식을 정의하는 개방형 표준(RFC 7519)입니다.
JWT의 구조와 작동 원리
JWT는 세 부분으로 구성됩니다. 헤더, 페이로드, 서명
- 헤더 : 토큰 유형과 사용된 해시 알고리즘 정보
- 페이로드 : 클레임(사용자 ID 등) 정보
- 서명 : 토큰의 유효성을 검증하는 데 사용
각 부분은 Base64Url로 인코딩되어 .
으로 구분됩니다.
JWT vs 세션 기반 인증
장점
- 서버 측 상태 저장 불필요 (무상태성)
- 확장성이 좋음 (서버 간 세션 공유 불필요)
- 모바일 애플리케이션에 적합
단점
- 토큰 크기가 세션 ID보다 큼
- 토큰 무효화가 어려움
- 중요 정보 저장 시 보안 위험
NestJS에 JWT 인증 구현
- 의존성 설치
- JWT 모듈 설정 (
app.module.ts
)
- AuthService 구현
- JWT 전략 구현
JWT 토큰 생성, 검증, 갱신
- 토큰 생성
- 토큰 검증
- 토큰 갱신
JWT 가드 생성 및 적용
- JWT 가드 생성
- 특정 라우트에 적용
- 전역 가드로 설정 (
main.ts
)
리프레시 토큰 메커니즘
- 리프레시 토큰 생성
- 리프레시 토큰 검증 및 새 액세스 토큰 발급
토큰 블랙리스팅/화이트리스팅
Redis를 사용한 토큰 블랙리스팅 예시
JWT 관련 보안 위협 대처
1. XSS 대응
- HttpOnly 쿠키 사용
- 컨텐츠 보안 정책(CSP) 설정
2. CSRF 대응
- CSRF 토큰 사용
- SameSite 쿠키 속성 설정
3. JWT 보안 설정
Best Practices와 성능 최적화
- 환경변수 사용 : JWT 비밀키를 환경변수로 관리
- 토큰 만료 시간 최소화 : 액세스 토큰의 수명을 짧게 유지 (15분-1시간)
- 비대칭 키 사용 고려 : RS256 알고리즘 사용
- 토큰 페이로드 최소화 : 필요한 정보만 포함
- 로깅 및 모니터링 : 비정상적인 토큰 사용 패턴 감지
- 정기적인 키 순환 : JWT 서명 키를 주기적으로 변경
- Rate Limiting 구현 : 토큰 생성 및 갱신 요청에 대한 제한 설정
- 에러 메시지 일반화 : 구체적인 에러 정보 노출 방지
- 토큰 저장소 사용 : 중요한 작업에 대해 서버 측 토큰 검증
- 성능 최적화
- 캐싱 사용 : 자주 사용되는 토큰 정보 캐싱
- 비동기 처리 : 토큰 검증 로직을 비동기로 구현
NestJS에서 JWT 기반 인증 시스템을 구축할 때는 보안과 성능의 균형을 잘 맞추는 것이 중요합니다.
JWT의 무상태성을 활용하여 확장성 있는 시스템을 구축할 수 있지만 동시에 토큰의 안전한 관리와 사용에 주의를 기울여야 합니다.
리프레시 토큰 메커니즘을 통해 액세스 토큰의 수명을 짧게 유지하면서도 사용자 경험을 해치지 않는 인증 시스템을 구현할 수 있습니다.
또한 토큰 블랙리스팅이나 화이트리스팅을 통해 필요 시 토큰을 무효화할 수 있는 유연성을 확보할 수 있습니다.