문제 상황
어떤 링크를 요청할 때 특정 사용자 또는 브라우저 환경에서 다음과 같은 예외가 발생하며 서버 응답이 실패하는 현상이 나타났습니다.
org.springframework.http.InvalidMediaTypeException: Invalid mime type "application/xhtml+xml": Invalid token character '+' in token "xhtml+xml"
at org.springframework.http.MediaType.parseMediaType(MediaType.java:534)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
...
이 오류는 Accept 헤더에 포함된 MIME 타입 파싱 과정에서 비정상적인 문자가 감지되었을 때 스프링 프레임워크 내부에서 발생합니다. 특히, 클라이언트에서 전송한 Accept: application/xhtml+xml 값에서 특수 기호 +(PLUS SIGN) 대신 +(일반 플러스)가 아닌 유니코드 기호가 사용된 경우 문제가 됩니다.
발생 환경
| 항목 | 사용 버전 |
|---|---|
| Spring Boot | 2.1.8.RELEASE |
근본 원인 분석
예외 메시지를 통해 MediaType.parseMediaType() 메서드가 비정상적인 토큰을 발견했다는 점을 알 수 있습니다. 디버깅을 통해 추적해보면, 문제는 클라이언트에서 전달된 Accept 헤더 값이 필터 체인을 거치면서 변조되는 데 있습니다.
특히, 애플리케이션에 적용된 XssFilter 클래스가 HTTP 요청 헤더 값을 사전에 인코딩하거나 치환하는 로직을 포함하고 있었으며, 이때 아래와 같은 코드가 문제를 일으켰습니다.
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
여기서 xssEncode() 함수가 입력값 내의 특수 문자를 치환하다 보니, 정상적인 + 문자가 유니코드 형태의 + (U+FF0B, FULLWIDTH PLUS SIGN)로 변경되어 전달되었습니다. 이 문자는 ASCII 범위를 벗어나며, MediaType 파서가 이를 유효한 토큰으로 인식하지 못해 예외가 발생하게 됩니다.
해결 방안
해당 필터가 헤더 값을 무분별하게 인코딩하지 않도록 수정해야 합니다. 특히 Accept, Content-Type과 같은 시스템 중요 헤더는 원본 값을 유지해야 하며, XSS 필터링은 본문 또는 쿼리 파라미터에 국한되어야 합니다.
수정된 필터 코드 예시:
public String getHeader(String name) {
// Accept 헤더는 인코딩 없이 그대로 반환
if ("accept".equalsIgnoreCase(name)) {
return super.getHeader(name);
}
// 다른 헤더에 대해서만 인코딩 적용
String value = super.getHeader(name);
if (value != null && shouldEncodeHeader(name)) {
value = xssEncode(value);
}
return value;
}
private boolean shouldEncodeHeader(String headerName) {
List<String> safeHeaders = Arrays.asList("accept", "content-type", "user-agent", "referer");
return !safeHeaders.contains(headerName.toLowerCase());
}
또는 더 근본적으로, XSS 필터는 요청 본문과 파라미터만 처리하고, 헤더는 건드리지 않도록 설계하는 것이 안전합니다.
검증 결과
수정 후 동일한 요청을 재시도했을 때, Accept 헤더가 정상적으로 파싱되었고, 더 이상 InvalidMediaTypeException이 발생하지 않았습니다. 모든 클라이언트 환경에서 안정적인 응답이 확인되었습니다.
요약 및 교훈
- HTTP 헤더는 시스템 동작에 직접 영향을 주므로, 필터에서 임의로 수정하면 안 됩니다.
- 특히
Accept,Content-Type등 미디어 타입 관련 헤더는 매우 민감합니다. - 유니코드 정규화 및 특수 문자 치환이 예상치 못한 위치에서 문제를 유발할 수 있으므로 주의가 필요합니다.
- 외부 라이브러리나 커스텀 필터를 사용할 때는 해당 컴포넌트가 어떤 방식으로 데이터를 조작하는지 반드시 검토해야 합니다.
- 디버깅은 의심되는 경로를 단계별로 추적함으로써 가장 빠르게 원인을 파악할 수 있습니다.