美文网首页
java-web过滤器-XSS

java-web过滤器-XSS

作者: 木果渣 | 来源:发表于2018-04-17 22:52 被阅读0次
    新项目为了防止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<String, String[]> 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<String, String[]> getParameterMap() {
                if (requestParams == null) {
                    requestParams = new HashMap<String, String[]>();
                    Map<String, String[]> originalQueryString = super.getParameterMap();
                    if (originalQueryString != null) {
                        for (Map.Entry<String, String[]> 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("<", "&lt;").replaceAll(">", "&gt;");
            value = value.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
            value = value.replaceAll("'", "&#39;");
            value = value.replaceAll("\"", "&#34;");
    
    
            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的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script> }
                String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>"; //定义style的正则表达式{或<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("\'", "&#39;");
                textStr = textStr.replaceAll("\"", "&#34;");
                textStr = textStr.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
                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

          本文链接:https://www.haomeiwen.com/subject/nokmkftx.html