风-fmgao

导航

springboot自定义CORS&XSS拦截器

springboot 项目前后端接口,防止xss攻击以及跨域问题解决

1、启动类添加注解

@ServletComponentScan

2、cors的拦截类

package com.longfor.hrssc.api.config;

import com.longfor.hrssc.common.util.ResultUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

@Component
@PropertySource("classpath:application-dev.yml")
@WebFilter(urlPatterns = "/*", filterName = "CorsFilter")
public class CorsFilter implements Filter {

    @Value("${bpm.fiter.domain}")
    private String allowDomains;

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest reqs = (HttpServletRequest) req;

        // 设置允许多个域名请求
        //String[] allowDomains = {"http://www.xxxx.xin","http://xxxx:8080","http://localhost:8080"};
        String[] allowDomain = allowDomains.split(",");
        Set allowOrigins = new HashSet(Arrays.asList(allowDomain));
        String curOrigin = reqs.getHeader("Origin");
        /*if("null".equalsIgnoreCase(curOrigin)){
            curOrigin = "http://xxxxxx:8888";
        }*/
        if(allowOrigins.contains(curOrigin) || null == curOrigin){
            //设置允许跨域的配置
            // 这里填写你允许进行跨域的主机ip(正式上线时可以动态配置具体允许的域名和IP)
            response.setHeader("Access-Control-Allow-Origin", curOrigin);
            response.setHeader("Access-Control-Allow-Credentials", "true");
            //response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");

            response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");

            response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, token");
            chain.doFilter(reqs, response);

        }else{
            throw new IOException(ResultUtils.doFilter().toString());
        }

    }

    @Override
    public void init(FilterConfig filterConfig) {}

    @Override
    public void destroy() {}
}

3、xss相关类

XssFilter
package com.longfor.hrssc.api.config;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/** * XSS过滤器 * @author Jozz */
@WebFilter(filterName="xssFilter",urlPatterns="/*")
public class XssFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest,
                                   ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest; String path = request.getServletPath();
        //由于我的@WebFilter注解配置的是urlPatterns="/*"(过滤所有请求),所以这里对不需要过滤的静态资源url,作忽略处理(大家可以依照具体需求配置)
        String[] exclusionsUrls = {".js",".gif",".jpg",".png",".css",".ico"};
        for (String str : exclusionsUrls) {
            if (path.contains(str)) {
                filterChain.doFilter(servletRequest,servletResponse);
                return;
            }
        }

        filterChain.doFilter(new XssHttpServletRequestWrapper(request),servletResponse);
    }
    @Override public void destroy() {

    }
}
XssHttpServletRequestWrapper

package com.longfor.hrssc.api.config;

/**
 * Created by 裴帅楠 on 2019/7/10.
 */
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
//import org.apache.commons.text.StringEscapeUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*; import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** * ServletRequest包装类,对request做XSS过滤处理
 * @author Jozz
 *
 * */

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }
        @Override
        public String getHeader(String name) {
        return StringEscapeUtils.escapeHtml4(super.getHeader(name));
    }

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

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

    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if(values != null) {
            int length = values.length;
            String[] escapseValues = new String[length];
            for(int i = 0; i < length; i++){
                escapseValues[i] = StringEscapeUtils.escapeHtml4(values[i]);
            }
            return escapseValues;
        }
        return values;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        String str=getRequestBody(super.getInputStream());
        Map<String,Object> map= JSON.parseObject(str,Map.class);
        Map<String,Object> resultMap=new HashMap<>(map.size());
        for(String key:map.keySet()){
            Object val=map.get(key);
            if(null != val){
                stripXss(val.toString());
            }

            if(map.get(key) instanceof String){
                resultMap.put(key,StringEscapeUtils.escapeHtml4(val.toString()));
            }else{
                resultMap.put(key,val);
            }
        }
        str=JSON.toJSONString(resultMap);

        final ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bais.read();
            }


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

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

            @Override
            public void setReadListener(ReadListener listener) {

            }
        };
    }



    private String getRequestBody(InputStream stream) {
        String line = "";
        StringBuilder body = new StringBuilder();
        int counter = 0;
        // 读取POST提交的数据内容
        BufferedReader reader = new BufferedReader(new InputStreamReader(stream, Charset.forName("UTF-8")));
        try {
            while ((line = reader.readLine()) != null) {
                body.append(line); counter++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } return body.toString();
    }

    private static List<Pattern> patterns = null;

    public static String stripXss(String value) {
        if(StringUtils.isNotBlank(value)) {
            Matcher matcher = null;
            for(Pattern pattern : getPatterns()) {
                matcher = pattern.matcher(value);
                // 匹配
                if(matcher.find()) {
                    // 删除相关字符串
                    value = matcher.replaceAll("");
                }
            }
            value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
        }
       /* if (LOG.isDebugEnabled()) {
          LOG.debug("strip value: " + value); return value;
        }*/
        return value;
    }

    private static List<Object[]> getXssPatternList() {
        List<Object[]> ret = new ArrayList<Object[]>();
        ret.add(new Object[]{"<(no)?script[^>]*>.*?</(no)?script>", Pattern.CASE_INSENSITIVE});
        ret.add(new Object[]{"eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        ret.add(new Object[]{"expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        ret.add(new Object[]{"(javascript:|vbscript:|view-source:)*", Pattern.CASE_INSENSITIVE});
        ret.add(new Object[]{"<(\"[^\"]*\"|\'[^\']*\'|[^\'\">])*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        ret.add(new Object[]{"(window\\.location|window\\.|\\.location|document\\.cookie|document\\.|alert\\(.*?\\)|window\\.open\\()*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        ret.add(new Object[]{"<+\\s*\\w*\\s*(oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondblclick|ondeactivate|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onerror=|onerroupdate|onfilterchange|onfinish|onfocus|onfocusin|onfocusout|onhelp|onkeydown|onkeypress|onkeyup|onlayoutcomplete|onload|onlosecapture|onmousedown|onmouseenter|onmouseleave|onmousemove|onmousout|onmouseover|onmouseup|onmousewheel|onmove|onmoveend|onmovestart|onabort|onactivate|onafterprint|onafterupdate|onbefore|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onblur|onbounce|oncellchange|onchange|onclick|oncontextmenu|onpaste|onpropertychange|onreadystatechange|onreset|onresize|onresizend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onselect|onselectionchange|onselectstart|onstart|onstop|onsubmit|onunload)+\\s*=+", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
        return ret;
    }
    private static List<Pattern> getPatterns() {
        if (patterns == null) {
            List<Pattern> list = new ArrayList<Pattern>();
            String regex = null;
            Integer flag = null;
            int arrLength = 0;
            for(Object[] arr : getXssPatternList()) {
                arrLength = arr.length; for(int i = 0; i < arrLength; i++) {
                    regex = (String)arr[0]; flag = (Integer)arr[1]; list.add(Pattern.compile(regex, flag));
                }
            }
            patterns = list;
        }
        return patterns;
    }

}

4、yml中配置

#bpm域名过滤
bpm:
  fiter:
    domain: http://xxx.sit,https://xxxxx.net:8089,http://xxxxx.sit:8088,http://xxxxx:8888,https://xxxxx:8443

5、返回

/**
     *  跨域白名单
     * @return
     */
    public static ResultUtils doFilter() {
        return new ResultUtils(Constants.doFilterCode, Constants.doFilterException, null);
    }

6、自定义code

public static final int doFilterCode  = 403;
public static final String doFilterException = "请申请IP白名单";

 





posted on 2019-07-10 15:01  风-fmgao  阅读(2725)  评论(0编辑  收藏  举报