XSS ?
Cross Site Scripting의 약자로, 웹 어플리케이션에 악의적으로 스크립트를 삽입하여 공격하는 기법이다.
Lucy-xss-servlet-filter ?
Naver에서 제공하는 오픈소스. 웹 어플리케이션으로 들어오는 모든 요청 파라미터에 대해 기본적인 XSS 방어 필터링을 수행한다. 아래와 같은 필터링 제외 설정을 제공한다.
- 설정한 url을 필터링에서 제외
- 설정한 prefix로 시작하는 파라미터를 필터링에서 제외
- 설정한 파라미터를 필터링에서 제외
이전에 lucy-xss-filter 라이브러리가 있었는데, 개발자가 수동으로 치환 로직을 일일히 추가해야 하는 방식으로 조치가 누락되는 경우가 많았다. 이에 대한 개선책으로 '자바 서블릿 필터 기반'의 라이브러리로 새로 나온 것이 'lucy-xss-servlet-filter'
[장점]
- XML(또는 gradle & yml) 설정만으로 XSS 방어 가능
- 비즈니스 레이어의 코드를 수정할 필요 없음
- 개발자가 XSS 방어를 신경쓰지 않아도 됨
- XSS 방어가 누락되지 않음
- 불필요한 곳에 XSS 방어 코드 적용 X
- 설정 파일만 보면 XSS 방어 절차 확인이 가능함
[단점]
- 파라미터명 관리가 필요함 (url, 파라미터prefix 등으로 필터링 대상을 설정함)
- 일괄 적용되기 때문에 필터링 룰 정의가 중요
(참고: https://github.com/naver/lucy-xss-servlet-filter)
Springboot에 적용하기
pom.xml, web.xml 추가 방식은 여기 참고: https://github.com/naver/lucy-xss-servlet-filter
1) build.gradle 에 dependency 추가하기
build.gradle 파일에 아래와 같이 dependency를 추가한다.
implementation 'com.navercorp.lucy:lucy-xss-servlet:2.0.0'
2) application.yml에 패키지명.web.xss.use-xss-filter 값을 true로 설정한다. (설정 값이 없으면 false 로 동작함)
-> true 로 설정하면 lucy-xss-sax.xml 파일에 설정한 정책을 기준으로 동작한다.
3) 적용할 HTML tag 설정하기
예외처리가 필요한 HTML tag를 lucy-xss-sax.xml 파일에 등록한다. Naver에서 제공하는 기본 설정이 있음. 적용 제외 하려면 disable="false"로 하거나 (disable="true" 여야 예외처리됨) 해당 행을 삭제하면 된다.
4) XSS Filter를 servletFilter에 등록하기
참고: https://github.com/naver/lucy-xss-servlet-filter/blob/master/doc/manual.md
예)
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://www.navercorp.com/lucy-xss-servlet">
<defenders>
<!-- 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>true</param-value> <!-- true: 주석없음, false: 주석있음. -->
</init-param>
</defender>
</defenders>
<!-- default defender 선언, 필터링 시 지정한 defender가 없으면 여기 정의된 default defender를 사용해 필터링 한다. -->
<default>
<defender>xssSaxFilterDefender</defender>
</default>
</config>
5) XSS Filter를 Bean으로 등록하기
파라미터에 설정 값이 적용될 수 있도록 Bean으로 등록한다.
예)
@Configuration
public class XssConfig implements WebMvcConfigurer {
@Value("${패키지명.web.xss.use-xss-filter:false}")
private boolean useXssFilter;
public XssConfig() {
}
@Bean
public FilterRegistrationBean getFilterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new XssEscapeServletFilter());
if (this.useXssFilter) {
registrationBean.addUrlPatterns(new String[]{"/*"});
} else {
registrationBean.addUrlPatterns(new String[]{"/_all_not_url_match_"});
}
return registrationBean;
}
}
6) XSS Filter를 RequestBody에 적용하기
RequestBodyAdvice를 상속받은 RequestBodyXssAdvice 파일을 만들어서 설정하고, @RestControllerAdvice 지정.
예)
@RestControllerAdvice
public class RequestBodyXssAdvice implements RequestBodyAdvice {
private final Environmet env;
private static final XssSaxFilter xssSaxFilter = XssSaxFilter.getInstance("lucy-xss-sax.xml", true);
public RequestBodyXssAdvice(Environment env) {
this.env = env;
}
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
return httpInputMessage;
}
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
String useXssFilterStr = this.env.getProperty("패키지명.web.xss.use-xss-filter");
boolean useXssFilter = "true".equalsIgnoreCase(useXssFilterStr);
if (useXssFilter) {
//String jsonStr = body to json String 작업
log.debug(".afterBodyRead(...): jsonStr = {}", jsonStr);
String xssEscapedJsonStr = xssSaxFilter.doFilter(jsonStr);
log.debug(".afterBodyRead(...): xssEscapedJsonStr = {}", xssEscapedJsonStr);
//return toObject(xssEscapedJsonStr, targetType); 작업
} else {
return body;
}
}
public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return body;
}
}
'Spring' 카테고리의 다른 글
웹서버, 웹애플리케이션서버, CGI (0) | 2023.05.21 |
---|---|
웹 서버 - 외장서버 vs 내장서버 (0) | 2023.05.21 |
application.properties VS application.yml (0) | 2023.04.24 |
스프링 AOP (0) | 2023.03.05 |
스프링, 스프링 부트의 등장 (0) | 2023.03.05 |