한국어

EDPS

Spring에서 JSON에 XSS 방지 처리 하기

조회 수 489 추천 수 0 2018.07.05 16:58:26

고마운 lucy-xss-servlet-filter의 한계

XSS(Cross Site Scripting) 방지를 위해 널리 쓰이는 훌륭한 lucy-xss-servlet-filter는 Servlet Filter 단에서 < 등의 특수 문자를 < 등으로 변환해주며, 여러 가지 관련 설정을 편리하게 지정할 수 있어 정말 좋다.

그런데 그 처리가 form-data에 대해서만 적용되고 Request Raw Body로 넘어가는 JSON에 대해서는 처리해주지 않는다는 단점이 있다. 그래서 JSON을 주고 받는 API 서버의 경우에는 직접 처리를 해줘야 한다.

lucy-xss-servlet-filter를 수정해서 JSON도 처리하도록 만드는 방법도 있겠지만, 여기에서는 Response를 클라이언트로 내보내는 단계에서 처리하는 방법을 알아본다.

HandlerInterceptor

Response 쪽에서 공통적으로 처리해줘야할 일이 있다면 금방 떠오르는 것이 HanderInterceptor의 postHandle()이다. 이 메서드의 파라미터는 HttpServletRequest requestHttpServletResponse responseObject handlerModelAndView modelAndView이고, response에서 Response Body를 꺼내서, < => < 등의 변환 처리를 하고 다시 response에 넣어주면 될 것 같다.

하지만 response에서 Response Body를 끄집어 내는 것도 쉽지 않고, 그 내용을 바꿔서 다시 집어넣는 것도 여의치 않다. 다른 방법이 필요하다.

MessageConverter

다음으로 생각나는 것은 MessageConverter다. 어차피 결국에는 Jackson 같은 Mapper를 통해 JSON 문자열로 Response에 담겨지므로, Mapper가 JSON 문자열을 생성할 때 XSS 방지 처리를 해주면 될 것 같다.

찾아보니 역시나 http://stackoverflow.com/questions/25403676/initbinder-with-requestbody-escaping-xss-in-spring-3-2-4 이런 자료가 있다. 좀 오래된 버전이고 군더더기도 있어서 Jackson 2.#, SpringBoot 1.# 버전 기준으로 깔끔하게, 그리고 커스터마이징 할 수 있는 부분을 추가해서 정리해봤다.

큰 흐름은 다음과 같다.

  1. 처리할 특수 문자 지정
  2. 특수 문자 인코딩 값 지정
  3. ObjectMapper에 특수 문자 처리 기능 적용
  4. MessageConverter에 ObjectMapper 설정
  5. WebMvcConfigurerAdapter에 MessageConverter 추가

처리할 특수 문자 지정

XSS 방지 처리할 특수 문자를 다음과 같이 CharacterEscapes를 상속한 클래스를 직접 만들어서 지정해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import com.fasterxml.jackson.core.SerializableString;
import com.fasterxml.jackson.core.io.CharacterEscapes;
import com.fasterxml.jackson.core.io.SerializedString;
import org.apache.commons.lang3.text.translate.AggregateTranslator;
import org.apache.commons.lang3.text.translate.CharSequenceTranslator;
import org.apache.commons.lang3.text.translate.EntityArrays;
import org.apache.commons.lang3.text.translate.LookupTranslator;

public class HTMLCharacterEscapes extends CharacterEscapes {

private final int[] asciiEscapes;

private final CharSequenceTranslator translator;

public HTMLCharacterEscapes() {

// 1. XSS 방지 처리할 특수 문자 지정
asciiEscapes = CharacterEscapes.standardAsciiEscapesForJSON();
asciiEscapes['<'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['>'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['&'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['\"'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['('] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes[')'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['#'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['\''] = CharacterEscapes.ESCAPE_CUSTOM;

// 2. XSS 방지 처리 특수 문자 인코딩 값 지정
translator = new AggregateTranslator(
new LookupTranslator(EntityArrays.BASIC_ESCAPE()), // <, >, &, " 는 여기에 포함됨
new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE()),
new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE()),
// 여기에서 커스터마이징 가능
new LookupTranslator(
new String[][]{
{"(", "("},
{")", ")"},
{"#", "#"},
{"\'", "'"}
}
)
);
}

@Override
public int[] getEscapeCodesForAscii() {
return asciiEscapes;
}

@Override
public SerializableString getEscapeSequence(int ch) {
return new SerializedString(translator.translate(Character.toString((char) ch)));

// 참고 - 커스터마이징이 필요없다면 아래와 같이 Apache Commons Lang3에서 제공하는 메서드를 써도 된다.
// return new SerializedString(StringEscapeUtils.escapeHtml4(Character.toString((char) ch)));
}
}

ObjectMapper에 특수 문자 처리 기능 적용 후 MessageConverter 등록

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Bean
public WebMvcConfigurerAdapter controlTowerWebConfigurerAdapter() {
return new WebMvcConfigurerAdapter() {

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);

// 5. WebMvcConfigurerAdapter에 MessageConverter 추가
converters.add(htmlEscapingConveter());
}

private HttpMessageConverter<?> htmlEscapingConveter() {
ObjectMapper objectMapper = new ObjectMapper();
// 3. ObjectMapper에 특수 문자 처리 기능 적용
objectMapper.getFactory().setCharacterEscapes(new HTMLCharacterEscapes());

// 4. MessageConverter에 ObjectMapper 설정
MappingJackson2HttpMessageConverter htmlEscapingConverter =
new MappingJackson2HttpMessageConverter();
htmlEscapingConverter.setObjectMapper(objectMapper);

return htmlEscapingConverter;
}
};
}

정리

lucy-xss-servlet-filter는 JSON에 대한 XSS는 처리해주지 않는다.

  • 따라서, JSON에 대한 XSS가 필요하다면
  • Jackson의 com.fasterxml.jackson.core.io.CharacterEscapes를 상속하는 클래스 A를 직접 만들어서 처리해야 할 특수문자를 지정하고,
  • ObjectMapper에 A를 설정하고,
  • ObjectMapper를 MessageConverter에 등록해서 Response가 클라이언트에 나가기 전에 XSS 방지 처리 해준다.

펌] http://homoefficio.github.io/2016/11/21/Spring%EC%97%90%EC%84%9C-JSON%EC%97%90-XSS-%EB%B0%A9%EC%A7%80-%EC%B2%98%EB%A6%AC-%ED%95%98%EA%B8%B0/
List of Articles
번호 제목 글쓴이 날짜 조회 수
202 [구글ebook의 ascm파일을 PDF 파일로 변환하기] [1] 수텐리 2019-01-08 39
201 sfc /scannow 명령 수텐리 2018-12-17 23
200 Detect Internet Explorer (IE) up to version 11 and Edge (12+) 수텐리 2018-11-28 40
199 추억의 Windows 95를 설치할 수 있는 방법 file 수텐리 2018-09-04 30
198 DVDfab passkey 수텐리 2018-08-26 46
197 GA 코드 관련 수텐리 2018-08-24 49
196 마인드맵 - XMind [1] 수텐리 2018-08-21 39
195 QA 테스트 자동화 툴의 개념과 대표적인 도구 10가지 소개 [1] 수텐리 2018-08-19 194
194 판매재고관리 프로그램 [1] 수텐리 2018-08-17 408
193 PM의 생산성을 '업'시켜줄 프로젝트 관리 툴 15선 WindBoy 2018-08-14 184
192 Find in file for windows 수텐리 2018-07-27 16
191 Internet 연결 시 IP 주소를 확인 WindBoy 2018-07-19 25
190 MS SQL에서 Table Description 추출하는 쿼리 수텐리 2018-07-10 106
» Spring에서 JSON에 XSS 방지 처리 하기 수텐리 2018-07-05 489
188 chart.js 활용하기 WindBoy 2018-06-18 108
187 [펌] postman 관련 WindBoy 2018-05-29 129
186 [블록체인플랫폼] ①이더리움, 블록체인 2.0 시대를 열다 [1] 수텐리 2018-05-23 29
185 Sublime Text를 사용 시 업데이트 안하는 방법 수텐리 2018-04-03 28
184 [Java] 자바 날짜, 시간 계산 예제 (1) 수텐리 2018-04-03 288
183 [Java] 자바 시간, 날짜 계산 (2) 수텐리 2018-04-03 123