build.gradle
implementation group: 'com.navercorp.lucy', name: 'lucy-xss-servlet', version: '2.0.1'
implementation group: 'com.navercorp.lucy', name: 'lucy-xss', version: '1.6.3'
lucy-xss-servlet-filter-rule.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://www.navercorp.com/lucy-xss-servlet">
<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 disable이 true이면 지정한 url 내의 모든 파라메터는 필터링 되지 않는다. -->
<url-rule>
<url disable="true">/</url>
</url-rule>
<!-- <url-rule>
<url disable="true">/app</url>
</url-rule> -->
<!-- 설정된 param은 필터링에서 제외된다. -->
<url-rule>
<url>/app/admin</url>
<params>
<param name="title" useDefender="false" />
</params>
</url-rule>
</url-rule-set>
</config>
lucy-xss-servlet-filter-rule.xml
mvcConfig.java
import com.fasterxml.jackson.databind.ObjectMapper;
import com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@RequiredArgsConstructor
public class MvcConfig implements WebMvcConfigurer {
private final ObjectMapper objectMapper;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/templates/", "classpath:/static/");
}
//Lucy xss filter 적용
@Bean
public FilterRegistrationBean<XssEscapeServletFilter> filterRegistrationBean() {
FilterRegistrationBean<XssEscapeServletFilter> filterRegistration = new FilterRegistrationBean<>();
filterRegistration.setFilter(new XssEscapeServletFilter());
filterRegistration.setOrder(1);
filterRegistration.addUrlPatterns("/*");
return filterRegistration;
}
//requestBody xss 필터 적용
@Bean
public MappingJackson2HttpMessageConverter jsonEscapeConverter() {
ObjectMapper copy = objectMapper.copy();
copy.getFactory().setCharacterEscapes(new XssCharacterEscapes());
return new MappingJackson2HttpMessageConverter(copy);
}
}
requestBody 처리는 따로 처리 해줘야 한다.
AppConfig.java
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@Configuration
public class AppConfig {
//xss
//local Date 데이터 타입을 거르기 위해 추가
@Bean
@Primary
public ObjectMapper objectMapper(){
return new Jackson2ObjectMapperBuilder()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.modules(new JavaTimeModule())
.timeZone("Asia/Seoul")
.build();
}
}
XssCharacterEscapes.java
import com.fasterxml.jackson.core.SerializableString;
import com.fasterxml.jackson.core.io.SerializedString;
import org.apache.commons.text.StringEscapeUtils;
public class XssCharacterEscapes extends com.fasterxml.jackson.core.io.CharacterEscapes {
private final int[] asciiEscapes;
public XssCharacterEscapes() {
// 1. XSS 방지 처리할 특수 문자 지정
asciiEscapes = com.fasterxml.jackson.core.io.CharacterEscapes.standardAsciiEscapesForJSON();
asciiEscapes['<'] = com.fasterxml.jackson.core.io.CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['>'] = com.fasterxml.jackson.core.io.CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['\"'] = com.fasterxml.jackson.core.io.CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['('] = com.fasterxml.jackson.core.io.CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes[')'] = com.fasterxml.jackson.core.io.CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['#'] = com.fasterxml.jackson.core.io.CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['\''] = com.fasterxml.jackson.core.io.CharacterEscapes.ESCAPE_CUSTOM;
}
@Override
public int[] getEscapeCodesForAscii() {
return asciiEscapes;
}
@Override
public SerializableString getEscapeSequence(int ch) {
return new SerializedString(StringEscapeUtils.escapeHtml4(Character.toString((char) ch)));
}
}
xss 방어용
'Framework > Spring' 카테고리의 다른 글
Spring Security 설정 6.x.x 버전 이상 (0) | 2024.10.14 |
---|---|
[PageHelper] 페이지 헬퍼 네비게이션 및 유틸 (1) | 2024.04.26 |
[setting] spring banner 바꾸는 법 (0) | 2023.10.13 |
[setting] logback 설정 (0) | 2023.10.13 |
[Java] mybatis mapping (0) | 2023.10.13 |