-
XSS 공격에 대한 방어스터디 2018. 9. 4. 16:04
프로젝트를 진행하며 XSS(Cross Site Scripting) 공격에 대한 방어를 하기 위해 네이버에서 개발한 Lucy-Xss-Servlet-Filter 라이브러리를 사용했습니다. 해당 라이브러리는 웹어플리케이션으로 들어오는 모든 요청 파라미터에 대해 기본적으로 XSS 방어 필터링을 수행합니다. 하지만 Lucy-Xss-Servlet-Filter 라이브러리는 form-data에 대해서만 적용되고 JSON에 대해서는 처리해주지 않는다는 단점이 있습니다. 이를 위해 별도로 Request Body로 넘어오는 JSON에 대한 필터를 등록해줬습니다. (마지막 부분에는 Lucy-Xss-Servlet-Filter를 사용하지않고 XSS 공격을 방어하는 법을 소개하겠습니다.)
Lucy-Xss-Servlet-Filter 라이브러리를 사용한 경우
우선, 방어를 위해 사용되어지는 XssEscapeServletFilter빈을 사용하기 위해서는 아래와 같이 의존성을 설정해 줍니다.
// xss-filter
compile('com.navercorp.lucy:lucy-xss-servlet:2.0.0')아래 코드는 XSS 필터를 설정하는 부분입니다.
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
...
// Form data
@Bean
public FilterRegistrationBean getXssEscapeServletFilterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new XssEscapeServletFilter());
registrationBean.setOrder(1);
registrationBean.addUrlPatterns("/api/reviews", "/chat"); //filter를 거칠 url patterns
return registrationBean;
}
// Request Body JSON
@Bean
public FilterRegistrationBean getRequestBodyXSSFileterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new RequestBodyXSSFileter());
registrationBean.addUrlPatterns("/api/reviews/update", "/chat"); //filter를 거칠 url patterns
return registrationBean;
}/resource 폴더 밑에 lucy-xss-servlet-filter-rule.xml 파일을 생성하고, 자신의 프로젝트에 맞게 필터링 룰을 작성합니다.
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://www.navercorp.com/lucy-xss-servlet">
<!-- XssPreventer 등록 -->
<defenders>
<!-- XssPreventer 등록 -->
<defender>
<name>xssPreventerDefender</name>
<class>com.navercorp.lucy.security.xss.servletfilter.defender.XssPreventerDefender</class>
</defender>
<!-- XssSaxFilter 등록 -->
<defender>
<name>xssSaxFilterDefender</name>
<class>com.navercorp.lucy.security.xss.servletfilter.defender.XssSaxFilterDefender</class>
<init-param>
<param-value>lucy-xss-sax.xml</param-value> <!-- lucy-xss-filter의 sax용 설정파일 -->
<param-value>false</param-value> <!-- 필터링된 코멘트를 남길지 여부, 성능 효율상 false 추천 -->
</init-param>
</defender>
<!-- XssFilter 등록 -->
<defender>
<name>xssFilterDefender</name>
<class>com.navercorp.lucy.security.xss.servletfilter.defender.XssFilterDefender</class>
<init-param>
<param-value>lucy-xss.xml</param-value> <!-- lucy-xss-filter의 dom용 설정파일 -->
<param-value>false</param-value> <!-- 필터링된 코멘트를 남길지 여부, 성능 효율상 false 추천 -->
</init-param>
</defender>
</defenders>
<!-- default defender 선언, 별다른 defender 선언이 없으면 default defender를 사용해 필터링 한다. -->
<default>
<defender>xssPreventerDefender</defender>
</default>
<!-- url 별 필터링 룰 선언 -->
<url-rule-set>
<url-rule>
<url>/api/reviews</url>
<params>
<param name="contents" useDefender="true"/>
<param name="orderFoodId" useDefender="false"/>
<param name="starPoint" useDefender="false"/>
<param name="page" useDefender="false"/>
<param name="filterId" useDefender="false"/>
</params>
</url-rule>
<url-rule>
<url>/api/reviews/update</url>
<params>
<param name="contents" useDefender="true"/>
<param name="orderFoodId" useDefender="false"/>
<param name="starPoint" useDefender="false"/>
</params>
</url-rule>
<url-rule>
<url>/chat</url>
<params>
<param name="message" useDefender="true"/>
<param name="roomId" useDefender="false"/>
</params>
</url-rule>
</url-rule-set>
</config>그런데 여기서 문제가 하나 발생했습니다.
진행하고있는 프로젝트에서 채팅을 위해 웹 소켓을 사용하고 있는데, 저는 당연히 Lucy-Xss-Servlet-Filter 라이브러리를 적용하면 채팅에서도 XSS 공격에 대한 방어가 될 것이라고 생각했습니다. 하지만 예상과 달리 웹소켓에서는 Lucy-Xss-Servlet-Filter 라이브러리가 적용되지 않았습니다.
따라서 채팅에서는 XSS 공격을 어떤식으로 방어 할지 고민한 끝에, Jackson Object매퍼가 JSON 문자열을 생성할 때 XSS 방지 처리를 해주면 될 것 같다는 생각이 들었습니다. 따라서, Jackson의 com.fasterxml.jackson.core.io.CharacterEscapes를 상속하는 HTMLCharacterEscapes 클래스를 직접 만들어서 처리해야 할 특수문자를 지정해줬습니다.
public class HTMLCharacterEscapes extends CharacterEscapes {
private final int[] asciiEscapes;
public HTMLCharacterEscapes() {
// XSS 방지 처리할 특수 문자 지정
asciiEscapes = CharacterEscapes.standardAsciiEscapesForJSON();
asciiEscapes['<'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['>'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['&'] = CharacterEscapes.ESCAPE_CUSTOM;
}
@Override
public int[] getEscapeCodesForAscii() {
return asciiEscapes;
}
@Override
public SerializableString getEscapeSequence(int ch) {
return new SerializedString(StringEscapeUtils.escapeHtml4(Character.toString((char) ch)));
}
}그 후, ObjectMapper에 생성한 클래스를 설정하고 ObjectMapper를 MessageConverter에 등록해서 Response가 클라이언트에 나가기 전에 XSS 공격에 대한 방어 처리를 해줬습니다.
@Slf4j
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
...
@Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
messageConverters.add(escapingConverter());
return true;
}
private MessageConverter escapingConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.getFactory().setCharacterEscapes(new HTMLCharacterEscapes());
MappingJackson2MessageConverter escapingConverter =
new MappingJackson2MessageConverter();
escapingConverter.setObjectMapper(objectMapper);
return escapingConverter;
}Lucy-Xss-Servlet-Filter 라이브러리를 사용하지 않은 경우
여기서 힌트를 얻어, 웹소켓 뿐 만 아니라 웹에서도 위와 같이 HttpMessageConverter를 이용하면 Lucy-Xss-Servlet-Filter 라이브러리를 걷어낼 수 있지 않을까? 라는 생각을 하게 됐습니다. 그리하여 아래와 같이 적용했더니 정상적으로 동작하는 것을 확인할 수 있었습니다.
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
...
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(escapingConverter());
}
@Bean
public HttpMessageConverter escapingConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.getFactory().setCharacterEscapes(new HTMLCharacterEscapes());
objectMapper.registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
MappingJackson2HttpMessageConverter escapingConverter =
new MappingJackson2HttpMessageConverter();
escapingConverter.setObjectMapper(objectMapper);
return escapingConverter;
}참고
https://github.com/naver/lucy-xss-servlet-filter
https://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/
'스터디' 카테고리의 다른 글
잘못된 URI 접근 시, 커스텀 에러 페이지로 이동 (1) 2018.09.04