현재 내 프로젝트의 구조는 다음과 같이 생겼다.
원래 api 모듈
에 로그인, 토큰 발급, 토큰 검증 로직이 있었는데 apigw
를 도입하면서 account
에 따로 JWT Token 검증 API를 생성해서
apigw
-> accout
모듈에서 Token 검증 후 라우팅 -> 목적지 서버
로 변경을 해줄려고 하다가 에러가 발생했다.
에러내용 : io.jsonwebtoken.UnsupportedJwtException: Signed Claims JWSs are not supported.
아마 많은 분들이 익숙한 코드일거라고 생각한다. 내 Validation 로직에서 parseClaimJwt
부분을 parseClaimJws
로 변경해주면 이 문제는 해결된다.
override fun validationTokenWithThrow(token: String?): Map<String, Any>? {
val key = Keys.hmacShaKeyFor(secretKey?.toByteArray())
val parser = Jwts
.parserBuilder()
.setSigningKey(key)
.build()
return try {
val result = token?.let { parser.parseClaimsJwt(it) }
HashMap(result?.body)
} catch (e: Exception) {
when (e) {
is SignatureException -> {
throw ApiException(TokenError.INVALID_TOKEN)
}
is ExpiredJwtException -> {
throw ApiException(TokenError.EXPIRED_TOKEN)
}
else -> {
throw ApiException(TokenError.TOEKN_EXCEPTION, e)
}
}
}
}
Intellij에서 shift + shift
를 누르고
Include non-project items
체크박스를 체크하고 DefaultJwtParser
를 검색하면 다음과 같은 코드가 나온다.
이는 JwtParser를 구현해놓은 구현부이고 위에서 사용하는 parseClaimJwt
나 parseClaimJws
함수가 여기에 구현되어 있다.
public <T> T parse(String compact, JwtHandler<T> handler)
함수 👇만약 이 코드에서 body가 instanceof Claims면 return handler.onClaimsJws((Jws<Claims>) jws);
구문에 의해서 Exception 발생
parseClaimJwt
에서는 parse()
함수를 통해서 claimJwt를 파싱하고 안되면 Signed JWSs are not supported
에러를 발생시키게 된다.
동적 분석을 하면서 분석을 해본 결과
parseClainJwt()
-> parse()
-> parse()
- (Jws<Claims>) jws 리턴
-> Exception 발생
문제는 parse 함수가 200줄이 넘어서 왜 (Jws<Claims>) jws
이 return 되는지 분석할 수 없었다..
parseClaimsJws(it)
: 이 메서드는 주어진 JWT(토큰)를 파싱하고, JWT가 서명된 JWT (JWS)임을 가정합니다. 즉, JWT가 서명되어 데이터 무결성이 확인되어야 합니다. JWS는 JSON Web Signature의 약어로, 데이터가 안전하게 전달되었음을 보장합니다.
parseClaimsJwt(it)
: 이 메서드는 주어진 JWT를 파싱하며, JWT에 서명 여부에 대한 가정을 하지 않습니다. 즉, JWT가 서명되었는지 여부를 확인하지 않고 데이터를 파싱합니다. 이 메서드는 서명이 없는 JWT (JWS가 아닌 경우) 또한 파싱할 수 있습니다.