본문 바로가기

JAVA

Java XSS Filter 적용

요약
1. 필터추가 (프로젝트별 방법 상이)
- WebInitializer.java (수정)

2. 소스추가
- XSSFilter.java

- XSSFilterWrapper.java

 

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ


상세
1. WebInitializer.java (수정)

- new XSSFilter() 추가

protected Filter[] getServletFilters() {
        OpenEntityManagerInViewFilter openEntityManagerInViewFilter = new OpenEntityManagerInViewFilter();
        openEntityManagerInViewFilter.setEntityManagerFactoryBeanName("entityManagerFactory");

        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);

        return new Filter[] {
                openEntityManagerInViewFilter,
                characterEncodingFilter,
                new DelegatingFilterProxy("springSecurityFilterChain"),
                new MDCInsertingServletFilter(),
                new XSSFilter(),
                new HiddenHttpMethodFilter(),
        };
    }



2. XSSFilter.java (추가)

- 필터 예외 URL 알맞게 수정

package com.plugin.xss;

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class XSSFilter implements Filter {

    public FilterConfig filterConfig;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String path = ((HttpServletRequest) request).getRequestURI();

        //필터 예외 URL 알맞게 수정
        if (!path.contains("/api/common")) {
            chain.doFilter(new XSSFilterWrapper((HttpServletRequest) request), response);
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void destroy() {
        this.filterConfig = null;
    }
}



3. XSSFilterWrapper.java (추가)

package com.plugin.xss;

import com.util.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.IOUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.util.Map;

@Slf4j
public class XSSFilterWrapper extends HttpServletRequestWrapper {
    private byte[] rawData;

    public XSSFilterWrapper(HttpServletRequest request) {
        super(request);

        try {
            InputStream inputStream = request.getInputStream();
            this.rawData = replaceXSS(IOUtils.toByteArray(inputStream));
        } catch (Exception e) {
            log.info(LogUtil.getFullLogMessage(e));
        }
    }

    // XSS replace
    private byte[] replaceXSS(byte[] data) {
        String strData = new String(data);
        strData = stripXSS(strData);
        return strData.getBytes();
    }

    private String replaceXSS(String value) {
        if (value != null) {
            value = stripXSS(value);
        }
        return value;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (this.rawData == null) {
            return super.getInputStream();
        }

        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.rawData);

        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
    }

    @Override
    public String getQueryString() {
        return replaceXSS(super.getQueryString());
    }

    @Override
    public String getParameter(String name) {
        return replaceXSS(super.getParameter(name));
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> params = super.getParameterMap();
        if (params != null) {
            params.forEach((key, value) -> {
                for (int i = 0; i < value.length; i++) {
                    value[i] = replaceXSS(value[i]);
                }
            });
        }

        return params;
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] params = super.getParameterValues(name);
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                params[i] = replaceXSS(params[i]);
            }
        }

        return params;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream(), "UTF-8"));
    }

    private String stripXSS(String value) {
        if (value != null) {
            //공통
            value = value.replaceAll("(?i)<script>(.*?)</script>", "");
            value = value.replaceAll("(?i)src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", "");
            value = value.replaceAll("(?i)src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", "");
            value = value.replaceAll("(?i)</script>", "");
            value = value.replaceAll("(?i)<script(.*?)>", "");
            value = value.replaceAll("(?i)eval\\((.*?)\\)", "");
            value = value.replaceAll("(?i)expression\\((.*?)\\)", "");

            //공공 가이드
            value = value.replaceAll("(?i)javascript", "");
            value = value.replaceAll("(?i)expressicharset", "");
            value = value.replaceAll("(?i)applet", "");
            //value = value.replaceAll("(?i)document", "");
            //value = value.replaceAll("(?i)meta", "");
            //value = value.replaceAll("(?i)string", "");
            //value = value.replaceAll("(?i)xml", "");
            value = value.replaceAll("(?i)create", "");
            value = value.replaceAll("(?i)blink", "");
            value = value.replaceAll("(?i)append", "");
            value = value.replaceAll("(?i)link", "");
            value = value.replaceAll("(?i)binding", "");
            //value = value.replaceAll("(?i)style", "");
            value = value.replaceAll("(?i)alert", "");
            value = value.replaceAll("(?i)script", "");
            value = value.replaceAll("(?i)msgbox", "");
            value = value.replaceAll("(?i)cnbeforeprint", "");
            value = value.replaceAll("(?i)embed", "");
            value = value.replaceAll("(?i)refresh", "");
            value = value.replaceAll("(?i)cnbeforepaste", "");
            //value = value.replaceAll("(?i)object", "");
            //value = value.replaceAll("(?i)void", "");
            value = value.replaceAll("(?i)iframe", "");
            value = value.replaceAll("(?i)cookie", "");
            value = value.replaceAll("(?i)frame", "");
            value = value.replaceAll("(?i)href", "");
            value = value.replaceAll("(?i)frameset", "");
            value = value.replaceAll("(?i)ilayer", "");
            value = value.replaceAll("(?i)layer", "");
            value = value.replaceAll("(?i)bgsound", "");
            //value = value.replaceAll("(?i)base", "");
            //value = value.replaceAll("(?i)title", "");
            value = value.replaceAll("(?i)vbscript", "");

            //공공 가이드 (event)
            value = value.replaceAll("(?i)onmousewheel(.*?)=", "");
            value = value.replaceAll("(?i)onactive(.*?)=", "");
            value = value.replaceAll("(?i)onfocusout(.*?)=", "");
            value = value.replaceAll("(?i)on(.*?)=", "");
            value = value.replaceAll("(?i)ondataavailable(.*?)=", "");
            value = value.replaceAll("(?i)oncut(.*?)=", "");
            value = value.replaceAll("(?i)onkeyup(.*?)=", "");
            value = value.replaceAll("(?i)onafteripudate(.*?)=", "");
            value = value.replaceAll("(?i)onclick(.*?)=", "");
            value = value.replaceAll("(?i)onkeypress(.*?)=", "");
            value = value.replaceAll("(?i)onmousedown(.*?)=", "");
            value = value.replaceAll("(?i)onchange(.*?)=", "");
            value = value.replaceAll("(?i)onload(.*?)=", "");
            value = value.replaceAll("(?i)onbeforeactivate(.*?)=", "");
            value = value.replaceAll("(?i)onbeforecut(.*?)=", "");
            value = value.replaceAll("(?i)onbounce(.*?)=", "");
            value = value.replaceAll("(?i)onbeforecopy(.*?)=", "");
            value = value.replaceAll("(?i)ondbclick(.*?)=", "");
            value = value.replaceAll("(?i)onmouseenter(.*?)=", "");
            value = value.replaceAll("(?i)onbeforedeactivate(.*?)=", "");
            value = value.replaceAll("(?i)ondeactivate(.*?)=", "");
            value = value.replaceAll("(?i)onmouseout(.*?)=", "");
            value = value.replaceAll("(?i)ondatasetchaged(.*?)=", "");
            value = value.replaceAll("(?i)ondrag(.*?)=", "");
            value = value.replaceAll("(?i)onmouseover(.*?)=", "");
            value = value.replaceAll("(?i)ondragend(.*?)=", "");
            value = value.replaceAll("(?i)onsubmit(.*?)=", "");
            value = value.replaceAll("(?i)ondragenter(.*?)=", "");
            value = value.replaceAll("(?i)onmouseend(.*?)=", "");
            value = value.replaceAll("(?i)onbeforeeditfocus(.*?)=", "");
            value = value.replaceAll("(?i)ondragleave(.*?)=", "");
            value = value.replaceAll("(?i)onresizestart(.*?)=", "");
            value = value.replaceAll("(?i)onbeforeuload(.*?)=", "");
            value = value.replaceAll("(?i)ondragover(.*?)=", "");
            value = value.replaceAll("(?i)onuload(.*?)=", "");
            value = value.replaceAll("(?i)onbeforeupdate(.*?)=", "");
            value = value.replaceAll("(?i)ondragstart(.*?)=", "");
            value = value.replaceAll("(?i)onselectstart(.*?)=", "");
            value = value.replaceAll("(?i)onpaste(.*?)=", "");
            value = value.replaceAll("(?i)onpropertychange(.*?)=", "");
            value = value.replaceAll("(?i)ondrop(.*?)=", "");
            value = value.replaceAll("(?i)onreset(.*?)=", "");
            value = value.replaceAll("(?i)onresize(.*?)=", "");
            value = value.replaceAll("(?i)ondatasetcomplete(.*?)=", "");
            value = value.replaceAll("(?i)onerror(.*?)=", "");
            value = value.replaceAll("(?i)onmove(.*?)=", "");
            value = value.replaceAll("(?i)onselect(.*?)=", "");
            value = value.replaceAll("(?i)oncellchange(.*?)=", "");
            value = value.replaceAll("(?i)onfinish(.*?)=", "");
            value = value.replaceAll("(?i)onstop(.*?)=", "");
            value = value.replaceAll("(?i)onlayoutcomplete(.*?)=", "");
            value = value.replaceAll("(?i)onfocus(.*?)=", "");
            value = value.replaceAll("(?i)onrowexit(.*?)=", "");
            value = value.replaceAll("(?i)onblur(.*?)=", "");
            value = value.replaceAll("(?i)onselectionchange(.*?)=", "");
            value = value.replaceAll("(?i)onerrorupdate(.*?)=", "");
            value = value.replaceAll("(?i)onbefore(.*?)=", "");
            value = value.replaceAll("(?i)onstart(.*?)=", "");
            value = value.replaceAll("(?i)onrowsinserted(.*?)=", "");
            value = value.replaceAll("(?i)onkeydown(.*?)=", "");
            value = value.replaceAll("(?i)onfilterchage(.*?)=", "");
            value = value.replaceAll("(?i)onmouseup(.*?)=", "");
            value = value.replaceAll("(?i)onfocusin(.*?)=", "");
            value = value.replaceAll("(?i)oncontrolselected(.*?)=", "");
            value = value.replaceAll("(?i)onrowsdelete(.*?)=", "");
            value = value.replaceAll("(?i)onlosecapture(.*?)=", "");
            value = value.replaceAll("(?i)onrowenter(.*?)=", "");
            value = value.replaceAll("(?i)onhelp(.*?)=", "");
            value = value.replaceAll("(?i)onreadystatechange(.*?)=", "");
            value = value.replaceAll("(?i)onmouseleave(.*?)=", "");
            value = value.replaceAll("(?i)onmousemove(.*?)=", "");
            value = value.replaceAll("(?i)oncontextmenu(.*?)=", "");
        }

        return value;
    }
}
반응형