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
https://m.blog.naver.com/haengro/220549463106
'PlayGround > 마실가실 리팩토링' 카테고리의 다른 글
[1년 후 마실가실] ExceptionHandlerFilter (0) | 2024.11.17 |
---|---|
[1년 후 마실가실] @GeneratedValue(strategy = GenerationType.IDENTITY) (0) | 2024.11.14 |
[1년 후 마실가실] Spring Security + JWT - Header (0) | 2024.11.03 |
[1년 후 마실가실] Spring Security + JWT - LoginFilter (0) | 2024.10.27 |
[1년 후 마실가실] User Error Code HttpStatus (1) | 2024.10.19 |