diff --git a/src/main/java/com/bio/bio_backend/global/filter/HttpLoggingFilter.java b/src/main/java/com/bio/bio_backend/global/filter/HttpLoggingFilter.java index 0bd92b0..6fc7270 100644 --- a/src/main/java/com/bio/bio_backend/global/filter/HttpLoggingFilter.java +++ b/src/main/java/com/bio/bio_backend/global/filter/HttpLoggingFilter.java @@ -112,6 +112,8 @@ public class HttpLoggingFilter extends OncePerRequestFilter { .replaceAll("(?i)(\"AccessToken\"\\s*:\\s*\")([^\"]+)(\")", "$1***$3") .replaceAll("(?i)(\"RefreshToken\"\\s*:\\s*\")([^\"]+)(\")", "$1***$3") .replaceAll("(?i)(\"authorization\"\\s*:\\s*\")([^\"]+)(\")", "$1***$3"); + // x-www-form-urlencoded 형태의 password 파라미터 마스킹 + masked = masked.replaceAll("(?i)(^|[&])password=([^&]*)", "$1password=***"); return masked; } @@ -120,11 +122,18 @@ public class HttpLoggingFilter extends OncePerRequestFilter { // 필요한 헤더만 추리거나, 전부 찍고 민감한 건 마스킹 Collections.list(request.getHeaderNames()).forEach(name -> { String value = request.getHeader(name); - if ("authorization".equalsIgnoreCase(name) && value != null) { - headers.put(name, value.startsWith("Bearer ") ? "Bearer ***" : "***"); - } else { - headers.put(name, value); + if (value == null) { + headers.put(name, null); + return; } + + if ("cookie".equalsIgnoreCase(name)) { + headers.put(name, maskCookieHeader(value)); + return; + } + + // 기타 헤더는 그대로 기록 (요구사항에 따라 최소 마스킹 적용) + headers.put(name, value); }); return headers.toString(); } @@ -132,11 +141,17 @@ public class HttpLoggingFilter extends OncePerRequestFilter { private String getResponseHeaders(HttpServletResponse response) { Map headers = new LinkedHashMap<>(); for (String name : response.getHeaderNames()) { - if ("authorization".equalsIgnoreCase(name)) { - headers.put(name, "***"); - } else { - headers.put(name, String.join(",", response.getHeaders(name))); + if ("set-cookie".equalsIgnoreCase(name)) { + List values = new ArrayList<>(response.getHeaders(name)); + List masked = new ArrayList<>(); + for (String v : values) { + masked.add(maskSetCookieHeader(v)); + } + headers.put(name, String.join(",", masked)); + continue; } + + headers.put(name, String.join(",", response.getHeaders(name))); } if (response.getContentType() != null) { headers.putIfAbsent("Content-Type", response.getContentType()); @@ -144,6 +159,24 @@ public class HttpLoggingFilter extends OncePerRequestFilter { return headers.toString(); } + // Cookie 헤더: "a=1; AccessToken=xxx; RefreshToken=yyy" 형태 중 AccessToken/RefreshToken만 마스킹 + private String maskCookieHeader(String cookieHeader) { + if (cookieHeader == null || cookieHeader.isEmpty()) return cookieHeader; + String masked = cookieHeader + .replaceAll("(?i)(^|;\\s*)(AccessToken)=([^;]*)", "$1$2=***") + .replaceAll("(?i)(^|;\\s*)(RefreshToken)=([^;]*)", "$1$2=***"); + return masked; + } + + // Set-Cookie: "AccessToken=xxx; Path=/; HttpOnly; ..." 형태 중 AccessToken/RefreshToken만 마스킹 + private String maskSetCookieHeader(String setCookie) { + if (setCookie == null || setCookie.isEmpty()) return setCookie; + String masked = setCookie + .replaceAll("(?i)^(AccessToken)=([^;]*)", "$1=***") + .replaceAll("(?i)^(RefreshToken)=([^;]*)", "$1=***"); + return masked; + } + @Override protected boolean shouldNotFilter(HttpServletRequest request) { String path = request.getRequestURI();