본문 바로가기
시큐어코딩/JAVA

(시큐어코딩)Java에서 JWT 기반 인증 및 보안 강화를 위한 Best Practice

by ICT 인사이트 2025. 4. 2.
728x90

1. JWT(Json Web Token)

JWT(Json Web Token)는 서버와 클라이언트 간 인증 정보를 안전하게 전달하기 위한 토큰 기반 인증 방식으로,
세션 상태를 유지하지 않고도 인증과 권한 부여를 구현할 수 있어 마이크로서비스, REST API, 모바일 앱에서 널리 사용됩니다.

그러나 잘못 구현된 JWT는 인증 우회, 토큰 위조, 탈취 등의 심각한 보안 문제로 이어질 수 있으므로, 정확한 구조 이해와 보안 Best Practice 적용이 필수입니다.


2. JWT 기본 구조 이해

JWT는 세 부분으로 구성되며 . 으로 구분됩니다:

Header.Payload.Signature

📦 구성 설명:

구성 요소 설명
Header 토큰 타입(JWT)과 서명 알고리즘 정보
Payload 사용자 정보 및 권한, 만료 시간 등 클레임 포함
Signature 비밀 키를 이용한 서명, 데이터 위·변조 방지

3. 취약한 JWT 인증 구현 예제

(1) 취약 코드: 검증 없이 디코딩

String token = request.getHeader("Authorization").substring(7);
String[] split = token.split("\\.");
String payload = new String(Base64.getDecoder().decode(split[1]));
System.out.println("Payload: " + payload); // ❌ 검증 없이 디코딩만 수행

문제점:

  • 서명(Signature) 검증 누락 → 공격자가 Payload를 수정한 가짜 토큰을 제출해도 무효화되지 않음
  • 알고리즘을 none으로 설정한 토큰도 통과 가능

4. 안전한 JWT 인증 구현 예제 (Java + jjwt 라이브러리)

(1) 토큰 생성

String jwt = Jwts.builder()
    .setSubject("user@example.com")
    .setIssuedAt(new Date())
    .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1시간 유효
    .signWith(SignatureAlgorithm.HS256, secretKey)
    .compact();

(2) 토큰 검증

Claims claims = Jwts.parser()
    .setSigningKey(secretKey)
    .parseClaimsJws(jwt)
    .getBody();

String username = claims.getSubject();

보안 강화 포인트:

  • 서명(Signature) 검증 필수
  • 유효 기간(exp) 반드시 설정
  • 기밀 키는 안전하게 관리 (예: 환경변수, Vault 등)

5. JWT 인증 보안 강화 Best Practices

Best Practice 설명
HS256 → RS256 사용 고려 대칭키 방식보다 공개/비공개 키 기반 비대칭 알고리즘이 더 안전
토큰 만료 시간 짧게 설정 일반적으로 15분~1시간 이내 권장
Refresh Token 전략 도입 Access Token이 만료된 후 자동 재발급
Secure, HttpOnly 쿠키 사용 토큰을 스토리지 대신 쿠키에 저장해 XSS, CSRF 방어
토큰 블랙리스트 적용 사용자 로그아웃 또는 탈퇴 시 토큰 무효화 필요
권한 정보는 최소한으로 Payload에 민감한 정보 포함 금지 (예: 비밀번호, 주민번호 등)

6. Spring Security + JWT 적용 예시

(1) JWT 필터 구현

public class JwtFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String token = resolveToken(request);
        if (token != null && validateToken(token)) {
            Authentication auth = getAuthentication(token);
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
        filterChain.doFilter(request, response);
    }
}

(2) 필터 등록

http.addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class);​
Spring Security와 연계하면 Role 기반 접근 제어, 필터 체인 통합 관리 가능

7. 결론

JWT는 편리하지만 정확한 검증과 안전한 설계 없이는 보안상 매우 위험할 수 있습니다.
OWASP에서도 강조하듯, 토큰 유효성 검증, 서명 알고리즘 강제화, 만료 전략 등 다층적 보안 기법을 적용하는 것이 필수입니다.

다음 포스팅:
다음 글에서는 "Spring Security 기반 권한 제어 실전 가이드 (RBAC 중심)"을 분석합니다.

 

728x90