Skip to content

Commit d878cf7

Browse files
authored
Merge pull request #372 from EAT-SSU/fix/#371-mask-sensitive-data-in-logs
fix: 인증 응답 로그 마스킹 처리
2 parents 43b98a2 + dcaddc3 commit d878cf7

3 files changed

Lines changed: 83 additions & 11 deletions

File tree

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
package ssu.eatssu.domain.admin.dto;
22

3-
public record LoginRequest(String loginId, String password) {
3+
import ssu.eatssu.global.log.annotation.LogMask;
4+
5+
public record LoginRequest(String loginId,
6+
@LogMask String password) {
47
}

src/main/java/ssu/eatssu/global/log/ControllerLogAspect.java

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
@RequiredArgsConstructor
3232
public class ControllerLogAspect {
3333

34+
private static final String RESPONSE_BODY_SKIPPED = "[response-body-skipped]";
35+
3436
private final ObjectMapper objectMapper;
3537
private final SlackErrorNotifier slackErrorNotifier;
3638

@@ -87,15 +89,7 @@ public Object logApi(ProceedingJoinPoint joinPoint) throws Throwable {
8789
Object result = joinPoint.proceed();
8890
long time = System.currentTimeMillis() - start;
8991

90-
String resultJson;
91-
try {
92-
resultJson = objectMapper.writeValueAsString(result);
93-
if (resultJson.length() > 600) {
94-
resultJson = resultJson.substring(0, 600) + "...(truncated)";
95-
}
96-
} catch (Exception e) {
97-
resultJson = String.valueOf(result);
98-
}
92+
String resultJson = getResponseLog(uri, result);
9993

10094
log.info("RESPONSE {} {} ({} ms) result={}", method, uri, time, resultJson);
10195
return result;
@@ -110,6 +104,26 @@ public Object logApi(ProceedingJoinPoint joinPoint) throws Throwable {
110104
}
111105
}
112106

107+
String getResponseLog(String uri, Object result) {
108+
if (isAuthApi(uri)) {
109+
return RESPONSE_BODY_SKIPPED;
110+
}
111+
112+
try {
113+
String resultJson = objectMapper.writeValueAsString(result);
114+
if (resultJson.length() > 600) {
115+
return resultJson.substring(0, 600) + "...(truncated)";
116+
}
117+
return resultJson;
118+
} catch (Exception e) {
119+
return String.valueOf(result);
120+
}
121+
}
122+
123+
private boolean isAuthApi(String uri) {
124+
return uri != null && uri.startsWith("/oauths/");
125+
}
126+
113127
private String getCauseMessage(Throwable e) {
114128
if (e instanceof BaseException baseException) {
115129
return baseException.getStatus().getMessage();
@@ -138,7 +152,7 @@ private String getDeviceTypeFromSecurityContext() {
138152
return "unknown";
139153
}
140154

141-
private Map<String, Object> toSafeMap(Object arg) {
155+
Map<String, Object> toSafeMap(Object arg) {
142156
Map<String, Object> result = new HashMap<>();
143157
for (Field field : arg.getClass().getDeclaredFields()) {
144158
field.setAccessible(true);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package ssu.eatssu.global.log;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import org.junit.jupiter.api.Test;
5+
import ssu.eatssu.domain.admin.dto.LoginRequest;
6+
import ssu.eatssu.domain.user.dto.Tokens;
7+
import ssu.eatssu.global.handler.response.BaseResponse;
8+
9+
import java.util.Map;
10+
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
13+
class ControllerLogAspectTest {
14+
15+
private final ControllerLogAspect controllerLogAspect = new ControllerLogAspect(new ObjectMapper(), null);
16+
17+
@Test
18+
void shouldSkipResponseBodyForOauthApi() throws Exception {
19+
// given
20+
BaseResponse<Tokens> response = BaseResponse.success(new Tokens("access-token", "refresh-token"));
21+
22+
// when
23+
String result = controllerLogAspect.getResponseLog("/oauths/kakao", response);
24+
25+
// then
26+
assertThat(result).isEqualTo("[response-body-skipped]");
27+
assertThat(result).doesNotContain("access-token", "refresh-token");
28+
}
29+
30+
@Test
31+
void shouldLogResponseBodyForNonOauthApi() throws Exception {
32+
// given
33+
BaseResponse<String> response = BaseResponse.success("ok");
34+
35+
// when
36+
String result = controllerLogAspect.getResponseLog("/meals", response);
37+
38+
// then
39+
assertThat(result).contains("ok");
40+
}
41+
42+
@Test
43+
void shouldMaskAnnotatedRequestFields() throws Exception {
44+
// given
45+
LoginRequest request = new LoginRequest("admin", "password");
46+
47+
// when
48+
Map<String, Object> result = controllerLogAspect.toSafeMap(request);
49+
50+
// then
51+
assertThat(result).containsEntry("loginId", "admin");
52+
assertThat(result).containsEntry("password", "***");
53+
}
54+
55+
}

0 commit comments

Comments
 (0)