요약
- Spring Security에서는 JWT에서 발생하는 예외에 대해 다양한 예외 메시지를 제공하고 있습니다.

변조된 토큰을 사용하는 경우.

토큰으로 아무 값이나 사용하는 경우.

토큰이 만료된 경우.
- 하지만 현 코드에서는 이러한 예외들을 적절히 활용하지 못하고 있는 상황입니다.
- 따라서 다음과 같이 개선할 것을 제안해봅니다!
AS-IS
tokenProvider.getAuthentication(token)에서 토큰 검증을 실행합니다.
- 검증 과정에서 문제 발생 시, 문제 종류에 관계없이 false가 반환됩니다.
- Authrization 토큰에 대한 split이 두번 시행됩니다.
|
@Override |
|
protected void doFilterInternal(HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response, jakarta.servlet.FilterChain filterChain) throws jakarta.servlet.ServletException, IOException { |
|
String token = tokenProvider.resolveToken(request); |
|
|
|
if (token != null && tokenProvider.validateToken(token)) { |
|
// check access token |
|
token = token.split(" ")[1].trim(); |
|
Authentication auth = tokenProvider.getAuthentication(token); |
|
SecurityContextHolder.getContext().setAuthentication(auth); |
|
} |
|
|
|
filterChain.doFilter(request, response); |
|
} |
|
// 토큰 검증 |
|
public boolean validateToken(String token) { |
|
try { |
|
// Bearer 검증 |
|
if (!token.substring(0, "BEARER ".length()).equalsIgnoreCase("BEARER ")) { |
|
return false; |
|
} else { |
|
token = token.split(" ")[1].trim(); |
|
} |
|
Jws<Claims> claims = Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token); |
|
// 만료되었을 시 false |
|
return !claims.getBody().getExpiration().before(new Date()); |
|
} catch (Exception e) { |
|
return false; |
|
} |
|
} |
TO-BE
simpleValidateToken(token)에서는 토큰 문자열 형식에 대해서만 검증을 실행합니다.
- 토큰 내부에 문제가 있을 시
tokenProvider.getAuthentication(token)에서 종류에 맞는 예외 발생
- 해당 예외처리는 (1) SecurityConfig 혹은 (2) ApiExceptionHandler @RestControllerAdvice 에서 적절히 처리하여 반환
@Override
protected void doFilterInternal(HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response, jakarta.servlet.FilterChain filterChain) throws jakarta.servlet.ServletException, IOException {
String token = tokenProvider.resolveToken(request);
// 토큰 문자열 형식에 대해 검증 ("Bearer xxxxx.xxxx.xxx")
simpleValidateToken(token);
// check access token
token = token.split(" ")[1].trim();
Authentication auth = tokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
filterChain.doFilter(request, response);
}
// 41xx : JWT Error
JWT_SIGNITURE_ERROR(4003, HttpStatus.UNAUTHORIZED, "손상된 JWT 토큰입니다."),
JWT_MALFORMED_ERROR(4004, HttpStatus.UNAUTHORIZED, "JWT 토큰이 올바르지 않습니다."),
JWT_EXPIRED_ERROR(4005, HttpStatus.UNAUTHORIZED, "JWT 토큰이 만료되었습니다."),
요약
변조된 토큰을 사용하는 경우.
토큰으로 아무 값이나 사용하는 경우.
토큰이 만료된 경우.
AS-IS
tokenProvider.getAuthentication(token)에서 토큰 검증을 실행합니다.LGTM-Backend/API-Server/src/main/java/swm/hkcc/LGTM/app/modules/auth/utils/jwt/JwtFilter.java
Lines 18 to 30 in 330785f
LGTM-Backend/API-Server/src/main/java/swm/hkcc/LGTM/app/modules/auth/utils/jwt/TokenProvider.java
Lines 94 to 109 in 330785f
TO-BE
simpleValidateToken(token)에서는 토큰 문자열 형식에 대해서만 검증을 실행합니다.tokenProvider.getAuthentication(token)에서 종류에 맞는 예외 발생