본문 바로가기
PlayGround/마실가실 리팩토링

[1년 후 마실가실] CharacterEncodingFilter

by HJ0216 2024. 11. 10.

1년 전 진행했던 마실가실 프로젝트를 🛠️리팩토링하며 정리한 내용입니다.

 

 

최근에 Security Filter를 리리팩토링하면서 기본 HttpStatus 값을 반환하여, Custom한 Error Code가 쓸 일이 없어졌습니다.

 

하지만, 쓰라고 만들어둔 것이기에 코드를 조금씩 바꿔서 response에 조심스럽게 담아 고객님께 전달해드렸는데 한글이 출력이 안됩니다.

 

하지만, 이 곳은 한국.. 한국어가 나와야 합니다..

 

검색해서 나온 방법들은 통하지 않아 네이버 블로그와 GPT와 함께 열심히 찾은 결과를 작성해둡니다..

 

(실패) application.yml

전역 설정의 중앙 허브.. application.yml 설정으로 먼저 시작해 봤습니다.

spring:
  servlet:
    encoding:
      charset: UTF-8
      force: true

 

charset을 UTF-8로 강제로 바꾸겠다는 의지는 통하지 않았습니다.

 

 

(실패) Filter.java
Response의 Header와 ContentType 설정

가장 많이 나온 해결 방법.. 하지만 제가 Postman에게 전달받은 글자는 물음표 뿐..

이 말은 즉, Postman도 저도 모르겠다는 의미입니다..

private void setResponse(HttpServletResponse response, ErrorCode errorCode) {
  response.setCharacterEncoding("UTF-8");
  response.setContentType("text/plain; charset=UTF-8");
  response.setStatus(errorCode.getHttpStatus().value());

  try {
    PrintWriter writer = response.getWriter();
    response.getWriter().write(errorCode.getMessage());
  } catch (IOException e) {
    log.warn(e.getMessage());
  }
}

 

 

(성공🎉)SecurityConfig.java
CharacterEncodingFilter 사용
public class SecurityConfig {
  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.addFilterBefore(characterEncodingFilter(), CsrfFilter.class);
  }


  @Bean
  public CharacterEncodingFilter characterEncodingFilter() {
    CharacterEncodingFilter filter = new CharacterEncodingFilter();
    filter.setEncoding("UTF-8");
    filter.setForceEncoding(true);
    return filter;
  }  
}

 

자, 이제 2가지 의문점을 해결해 봅시다.

1. 왜 Filter 설정을 해야만 한글을 볼 수 있는가.

응답에서 직접 한글 인코딩을 진행할 경우, 이미 초기화된 기본 인코딩을 덮어쓰지 못하는 경우가 발생할 수 있음

 

response.getWriter()를 호출하면 서블릿 컨테이너가 해당 응답을 "커밋"(commit)하게 되는데, 이 과정에서 콘텐츠 타입과 인코딩이 이미 지정된 상태로 고정됨

→ 그 후, setHeader("Content-Type", "text/plain; charset=UTF-8")나 setCharacterEncoding("UTF-8") 같은 설정이 더 이상 반영되지 않음

→ 한글이 제대로 출력되지 않음

  * 기존 코드의 경우, Header 설정을 getWriter() 호출 전 사용하긴 했으나, Spring Security가 적용된 환경에서는 인코딩 설정이 제대로 반영되지 않을 가능성이 있음

    Spring Security나 다른 필터들이 응답 처리를 할 때, 인코딩 설정을 덮어쓰거나 변경하는 경우가 발생할 수 있기 때문

 

2. csrfFilter는 누구시고, 왜 그전에 설정해야 하는가.

csrfFilter: 사이트 간 요청 위조를 방지하는 필터, 요청마다 고유한 CSRF 토큰을 생성하고 이를 검증하는 역할

  * CSRF 토큰 : 사용자가 서버에 로그인하거나 새 세션을 시작하면, 서버는 CSRF 토큰을 생성하고 이를 세션에 저장

  * CSRF: 악의적인 사이트가 사용자를 대신해 신뢰된 사이트에 요청을 보내게 하여 피해를 입히는 공격 방식

    예: 사용자가 은행에 로그인한 상태에서 악의적인 사이트를 방문하면 악의적인 사이트가 사용자 몰래 계좌 이체 등의 요청을 보낼 수 있음

 

CharacterEncodingFilter는 요청과 응답의 문자 인코딩을 설정하는 필터로, 요청 본문이나 응답에 대한 인코딩을 처리함
인코딩 여부에 영향을 미치는 필터들 중 가장 앞에 위치해야 하고, 보통 인코딩 영향을 받는 필터 중 첫 번째가 CSRF 필터
CSRF 토큰 검증 필터(CsrfFilter) 이후 설정 시, CsrfFilter나 그 외 다른 보안 필터가 요청 본문에 접근할 때 이미 잘못된 인코딩이 적용될 수 있음
CsrfFilter가 요청의 인코딩을 고려하지 않고 바로 검증을 수행하는 구조이기 때문에, 인코딩이 올바르게 적용되지 않은 상태에서 필터가 실행되면 CSRF 필터를 포함한 이후 필터들이 요청을 잘못 해석할 수도 있게 됨
CSRF 보호가 비활성화되어도 다른 필터들이 요청 본문이나 응답을 처리할 때 올바른 인코딩이 적용되어야 하기 때문에, CharacterEncodingFilter는 CSRF 설정과 무관하게 항상 앞단에 두는 것이 권장

 

 

 

🙋‍♀️

본 포스트는 공부 목적으로 작성하였습니다.
보시는 도중 잘못된 부분이나 개선할 부분이 있다면 댓글로 알려주시면 수정하도록 하겠습니다.

 

📑

참고 자료

https://velog.io/@choonbok22/230314-TIL-32

 

230314 TIL #32 getWriter() 한글 깨짐

Spring 3주차.1 getWriter() 한글 깨짐

velog.io

https://m.blog.naver.com/haengro/220549463106

 

Spring에서의 한글깨짐 문제 (Spring Security 사용시)

개인 프로젝트를 진행하기위해 가장 최신버전의 Spring을 적용해서 웹페이지를 개발하기로 결정했다 그외...

blog.naver.com