java-web过滤器-XSS

新项目为了防止XSS攻击,直接把所有的html标签都过滤成""了,导致有个地方需要编辑存储富文本的功能用不了了/(ㄒoㄒ)/~~,产品让我改,我表示还没写过专门针对富文本的过滤器,我也没好好研究过javaWeb的过滤器,今天学习了一下。写了个比较简单的针对XSS攻击的过滤器。

基本思路就是把http请求的参数拦截下来,针对一些特殊的字符过滤一遍。
首先写一个过滤器。

public class XSSFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        ModifyParametersWrapper wrapper = new ModifyParametersWrapper((HttpServletRequest) httpServletRequest);
        filterChain.doFilter(wrapper, httpServletResponse);
    }
     /**
     * 继承HttpServletRequestWrapper,创建装饰类,以达到修改HttpServletRequest参数的目的
     */
    private class ModifyParametersWrapper extends HttpServletRequestWrapper {

        private Map requestParams;

        public ModifyParametersWrapper(HttpServletRequest request) {
            super(request);
        }

        /**
         * 获取指定参数名的值,如果有重复的参数名,则返回第一个的值 接收一般变量 ,如text类型
         *
         * @param name 指定参数名
         * @return 指定参数名的值
         */
        @Override
        public String getParameter(String name) {
            String parameter = null;
            String[] vals = getParameterMap().get(name);

            if (vals != null && vals.length > 0) {
                parameter = vals[0];
            }

            return parameter;
        }

        /**
         * 获取指定参数名的所有值的数组
         */
        @Override
        public String[] getParameterValues(String name) {
            return getParameterMap().get(name);
        }

        @Override
        public Map getParameterMap() {
            if (requestParams == null) {
                requestParams = new HashMap();
                Map originalQueryString = super.getParameterMap();
                if (originalQueryString != null) {
                    for (Map.Entry entry : originalQueryString.entrySet()) {
                        //对参数名进行过滤
                        String key = HTMLFilterUtil.cleanXSS(entry.getKey());
                        //对每个传参进行过滤
                        String[] rawValues = entry.getValue();
                        String[] filteredValues = new String[rawValues.length];
                        for (int i = 0; i < rawValues.length; i++) {
                              //具体的过滤规则
                            filteredValues[i] = HTMLFilterUtil.cleanXSS((rawValues[i]));
                        }
                        requestParams.put(key, filteredValues);
                    }
                }
            }
            return requestParams;
        }
}

具体的过滤规则
 /**
     * 标签部分转译
     * @param value
     * @return
     */
    public static String cleanXSS(String value) {
        //屏蔽掉xss攻击和sql注入等危险字符
        value = value.replaceAll("<", "<").replaceAll(">", ">");
        value = value.replaceAll("\\(", "(").replaceAll("\\)", ")");
        value = value.replaceAll("'", "'");
        value = value.replaceAll("\"", """);


        value = value.replaceAll("\\\\", "");
        value = value.replaceAll("\\\\/", "");

        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("e-xpression\\\\((.*?)\\\\)\"", "");

        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("[\\\"\\\'][\\s]*vbscript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("[\\\"\\\'][\\s]*onload:(.*)[\\\"\\\']", "\"\"");
        return value;
    }

 /**
     * 标签全过滤
     * @param inputString
     * @return
     */
    public static String Html2Text(String inputString) {
        String htmlStr = inputString; //含html标签的字符串
        String textStr = "";
        java.util.regex.Pattern p_script;
        java.util.regex.Matcher m_script;
        java.util.regex.Pattern p_style;
        java.util.regex.Matcher m_style;
        java.util.regex.Pattern p_html;
        java.util.regex.Matcher m_html;

        try {
            String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>"; //定义script的正则表达式{或]*?>[\\s\\S]*?<\\/script> }
            String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>"; //定义style的正则表达式{或]*?>[\\s\\S]*?<\\/style> }
            String regEx_html = "<[^>]+>"; //定义HTML标签的正则表达式

            p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
            m_script = p_script.matcher(htmlStr);
            htmlStr = m_script.replaceAll(""); //过滤script标签

            p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
            m_style = p_style.matcher(htmlStr);
            htmlStr = m_style.replaceAll(""); //过滤style标签

            p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
            m_html = p_html.matcher(htmlStr);
            htmlStr = m_html.replaceAll(""); //过滤html标签

            textStr = htmlStr;
            // 过滤单双引号
            textStr = textStr.replaceAll("\'", "'");
            textStr = textStr.replaceAll("\"", """);
            textStr = textStr.replaceAll("\\(", "(").replaceAll("\\)", ")");
            textStr = textStr.replaceAll("eval\\((.*)\\)", "");
            textStr = textStr.replaceAll("\\\\", "");
            textStr = textStr.replaceAll("\\\\/", "");

        } catch (Exception e) {
            System.err.println("Html2Text: " + e.getMessage());
        }

        return textStr;
    }

这样可以过滤掉@RequestParam的参数,但是如果要过滤直接post的json字符串需要重写以下方法。

        private byte[] requestBody = null;

        public ModifyParametersWrapper(HttpServletRequest request) {
            super(request);
            try {
                requestBody = StreamUtils.copyToByteArray(request.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @Override
        public ServletInputStream getInputStream() throws IOException {
            if (requestBody == null) {
                requestBody = new byte[0];
            }
            //可以对字符串进行操作,但是我觉得json这种的还是反序列话为对象之后再处理比较好,
            String json = new String(requestBody, "UTF-8");
            final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
            return new ServletInputStream() {
                @Override
                public int read() throws IOException {
                    return bais.read();
                }

                @Override
                public boolean isFinished() {
                    return false;
                }

                @Override
                public boolean isReady() {
                    return true;
                }

                @Override
                public void setReadListener(ReadListener listener) {

                }
            };
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }

最后需要把过滤器配置好。
下面是配置多个过滤器的方法。

@Configuration
public class FilterConfig {

    /**
     * 配置过滤器
     * 按照order值的大小,从小到大的顺序来依次过滤
     * @return
     */
    @Bean
    @Order(Integer.MAX_VALUE - 1)
    public FilterRegistrationBean someFilterRegistration1() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(xssFilter());
        registration.addUrlPatterns("/filter/*");
        registration.addInitParameter("paramName", "paramValue");
        registration.setName("xssFilter");
        return registration;
    }

    /**
     * 配置过滤器
     * 按照order值的大小,从小到大的顺序来依次过滤
     * @return
     */
    @Bean
    @Order(Integer.MAX_VALUE)
    public FilterRegistrationBean someFilterRegistration2() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(sessionFilter());
        registration.addUrlPatterns("/session/*");
        registration.addInitParameter("paramName", "paramValue");
        registration.setName("sessionFilter");
        return registration;
    }


    /**
     * 创建一个bean
     * @return
     */
    @Bean(name = "xssFilter")
    public Filter xssFilter() {
        return new XSSFilter();
    }
    /**
     * 创建一个bean
     * @return
     */
    @Bean(name = "sessionFilter")
    public Filter sessionFilter() {
        return new SessionFilter();
    }
}

这样一个基本的过滤器就完成了。

你可能感兴趣的:(java-web过滤器-XSS)