Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[개선] JWT 에서 데이터 Claim시 서명 알고리즘의 명시적 선언 필요 #149

Merged
merged 5 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/docs/asciidoc/auth.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ include::{snippets}/auth-controller-test/액세스_토큰으로_액세스_토큰
===== 리프레시 토큰을 보내지 않은 경우
include::{snippets}/auth-controller-test/액세스_토큰을_재발급할_때_리프레시_토큰을_보내지_않으면_에러가_발생한다/http-response.adoc[]

===== 서명 알고리즘이 불일치 하는 경우
include::{snippets}/auth-controller-test/토큰의_서명_알고리즘이_불일치하면_에러가_발생한다/http-response.adoc[]

=== 로그아웃
로그인 한 사용자는 로그아웃 할 수 있습니다.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import com.bamdoliro.maru.domain.user.service.UserFacade;
import com.bamdoliro.maru.infrastructure.persistence.auth.TokenRepository;
import com.bamdoliro.maru.shared.config.properties.JwtProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
Expand All @@ -18,7 +21,9 @@

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Base64;
import java.util.Date;
import java.util.Map;

@RequiredArgsConstructor
@Service
Expand Down Expand Up @@ -71,6 +76,8 @@ public String getType(String token) {

private Claims extractAllClaims(String token) {
try {
validateSignatureAlgorithm(token);

return Jwts.parserBuilder()
.setSigningKey(getSigningKey(jwtProperties.getSecretKey()))
.build()
Expand All @@ -83,6 +90,19 @@ private Claims extractAllClaims(String token) {
}
}

private void validateSignatureAlgorithm(String token) throws JsonProcessingException {
String[] tokenParts = token.split("\\.");
String headerJson = new String(Base64.getDecoder().decode(tokenParts[0]));

ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> headerMap = objectMapper.readValue(headerJson, new TypeReference<>() {});
String algorithm = (String) headerMap.get("alg");

if (!algorithm.equals(SignatureAlgorithm.HS256.getValue())) {
throw new InvalidTokenException();
}
}

private Key getSigningKey(String secretKey) {
byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
return Keys.hmacShaKeyFor(keyBytes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,22 @@ class AuthControllerTest extends RestDocsTestSupport {
verify(refreshTokenUseCase, never()).execute(anyString());
}

@Test
void 토큰의_서명_알고리즘이_불일치하면_에러가_발생한다() throws Exception {
String accessToken = AuthFixture.createAccessTokenString();
doThrow(new InvalidTokenException()).when(refreshTokenUseCase).execute(accessToken);

mockMvc.perform(patch("/auth")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.header("Refresh-Token", accessToken)
)

.andExpect(status().isUnauthorized())

.andDo(restDocs.document());
}

@Test
void 유저가_로그아웃한다() throws Exception {
User user = UserFixture.createUser();
Expand Down
Loading