zoukankan      html  css  js  c++  java
  • springboot Xss(跨站攻击)

    springboot Xss(跨站脚本攻击)

    跨站脚本攻击(Cross Site Scripting),为了不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

    #依赖

            <dependency>
                <groupId>org.jsoup</groupId>
                <artifactId>jsoup</artifactId>
                <version>1.13.1</version>
            </dependency>
            <!-- BooleanUtils在该依赖下 -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.10</version>
            </dependency>

    #工具类


    /**
     * xss过滤工具
     */
    public class JsoupUtils {
        //设置白名单
        private static final Whitelist WHITELIST = Whitelist.basicWithImages();
        //配置过滤参数不对代码格式化
        private static final Document
                .OutputSettings OUTPUT_SETTINGS = new Document
                //默认开启,关闭输入的代码格式化
                .OutputSettings().prettyPrint(false);
    ​
        static {
            //为标签添加属性,使用伪标签(:all表示所有标签),这里指白名单中的标签
            //允许富文本编辑器设置行内样式
            WHITELIST.addAttributes(":all", "style");
        }
    ​
        /**
         * content是用户输入的内容,没有baseUri,所以设置空
         * 过滤,如果不需要baseUri 就使用空字符串
         * 从不信任的html片段中截取信任的片段
         */
        public static String clean(String content) {
            return Jsoup.clean(content, "", WHITELIST, OUTPUT_SETTINGS);
        }
        /*
         这里能发现事件被过滤了  
        public static void main(String[] args) {
           String text = "<a href="http://www.baidu.com/a" onclick="alert(1);">sss</a><script>alert(0);</script>sss";
           System.out.println(clean(text));
        }
         */
    }

    #request包装类


    /**
     * 核心
     * 过滤http请求中参数包含的恶意字符
     * 需要重写getParameter,getParameterValues,getHeader
     */
    public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
        //原始的请求
        public HttpServletRequest orgRequest;
        //是否包含富文本
        private boolean isIncludeRichText;
    ​
    ​
        public XssHttpServletRequestWrapper(HttpServletRequest request, boolean isIncludeRichText) {
            super(request);
            orgRequest = request;
            this.isIncludeRichText = isIncludeRichText;
        }
    ​
        public boolean isIncludeRichText() {
            return isIncludeRichText;
        }
    ​
        public void setIncludeRichText(boolean includeRichText) {
            isIncludeRichText = includeRichText;
        }
    ​
        /**
         * 过滤请求头
         */
        @Override
        public String getHeader(String name) {
            JsoupUtils.clean(name);
            String header = super.getHeader(name);
            if (!StringUtils.isEmpty(header)) {
                return JsoupUtils.clean(name);
            }
            return header;
        }
    ​
        /**
         * 过滤请求的参数和值
         * 覆盖getParameter方法,将参数名和参数值都做xss过滤。
         * 如果需要获得原始的值,则通过super.getParameterValues(name)来获取
         * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
         */
        @Override
        public String getParameter(String name) {
            boolean condition = Objects.equals("content", name) || name.endsWith("WithHtml");
            //如果请求的参数为content或是以WithHtml结尾的,且不包含富文本
            if (condition && !isIncludeRichText) {
                //不过滤参数
                return super.getParameter(name);
            }
            //过滤参数
            JsoupUtils.clean(name);
            String value = super.getParameter(name);
            //如果值不为null和空字符串""( " "不算空字符串因为就是判断长度)过滤值
            if (!StringUtils.isEmpty(value)) {
                JsoupUtils.clean(value);
            }
            return value;
        }
    ​
        /**
         * 过滤单个参数多个值
         * 如复选框
         */
        @Override
        public String[] getParameterValues(String name) {
            String[] values = super.getParameterValues(name);
            for (int i = 0; i < values.length; i++) {
                //过滤值后重新赋值
                values[i] = JsoupUtils.clean(values[i]);
            }
            return values;
        }
    ​
        public HttpServletRequest getOrgRequest() {
            return orgRequest;
        }
    ​
        public void setOrgRequest(HttpServletRequest orgRequest) {
            this.orgRequest = orgRequest;
        }
    ​
        /**
         * 获取原始的request请求
         */
        public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
            if (request instanceof XssHttpServletRequestWrapper) {
                return ((XssHttpServletRequestWrapper) request).getOrgRequest();
            }
            return request;
        }
    }
    ​
     

    #filter

    /**
     * XssFilter过滤Xss请求的入口
     * 拦截防止xss
     */
    @Slf4j
    public class XssFilter implements Filter {
        //LoggerFactory log = LoggerFactory.getLogger(XssFilter.class)
        //是否包含富文本内容
        public static boolean IS_INCLUDE_RICH_TEXT = false;
    
        public List<String> excludes = new ArrayList<>();
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            log.debug("----------------- xss filter init ----------------");
            //获取filter中的初始参数
            String isRichText = filterConfig.getInitParameter("isIncludeRichText");
            if (!StringUtils.isEmpty(isRichText)) {
                //将字符串转为布尔
                IS_INCLUDE_RICH_TEXT = BooleanUtils.toBoolean(isRichText);
            }
            String temp = filterConfig.getInitParameter("excludes");
            if (!StringUtils.isEmpty(temp)) {
                String[] url = temp.split(",");
                //spring工具类
                Assert.notNull(url, "exclude不能为null");
                excludes.addAll(Arrays.asList(url));
            }
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            log.debug("----------------------xss filter is open----------------------");
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            if (handleExcludeURL(req, resp)) {
                //包含exclude的url片段放行
                chain.doFilter(request, response);
                return;
            }
            //不包含exclude的url片段
            //将request包装到XssHttpServletRequestWrapper
            XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
                    (HttpServletRequest) request, IS_INCLUDE_RICH_TEXT);
            //放行,交给spring处理
            chain.doFilter(xssRequest, response);
        }
    
        private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
            //spring工具类,判断集合是否为空集合或集合为null
            if (CollectionUtils.isEmpty(excludes)) {
                return false;
            }
            //获取请求的servletPath,不带协议+ip+端口+项目名
            String servletPath = request.getServletPath();
            for (String pattern : excludes) {
                //这里的^表示匹配开头
                Pattern p = Pattern.compile("^" + pattern);
                //String实现CharSequence, 用pattern去匹配servlet
                Matcher matcher = p.matcher(servletPath);
                //判断请求的servletPath中是否有匹配pattern的,只要有一个就返回true
                if (matcher.find()) {
                    return true;
                }
            }
            return false;
        }
    }
     

    #配置类


    @Configuration
    public class JsoupConf {
        /**
         * 注册jsoup Filter
         */
        @Bean
        public FilterRegistrationBean<XssFilter> xssfilterRegistrationBean() {
            FilterRegistrationBean<XssFilter> filterRegistrationBean =
                    new FilterRegistrationBean<>(new XssFilter());
            //filterRegistrationBean.setFilter(new XssFilter());
            //设置在filter中执行的顺序,为第一执行
            filterRegistrationBean.setOrder(1);
            //指明filter是否开启,默认开启
            filterRegistrationBean.setEnabled(true);
            //拦截所有请求
            filterRegistrationBean.addUrlPatterns("/*");
            HashMap<String, String> initParmas = new HashMap<>();
            //路径自行替换为static下的,首页
            initParmas.put("excludes", "/favicon.ico,/img/*,/js/*,/css/*,/index");
            initParmas.put("isIncludeRichText", "true");
            //设置filter的init-param
            filterRegistrationBean.setInitParameters(initParmas);
            return filterRegistrationBean;
        }
    }
    参考:
    https://www.jianshu.com/p/3e4b00b8ff3a
    https://www.open-open.com/jsoup/

     

  • 相关阅读:
    web service 入门实例
    ideal 创建web service项目
    win10上配置hadoop环境
    hadoop-----slaves集中管理与SSH免密登录
    关系的完整性
    关系数据库-----SQL标准语言
    mysql导入excel文件---打开文件失败
    CC2540中的电压检测
    C++ 中静态成员函数访问非静态成员变量的方法
    C 语言中的优先级
  • 原文地址:https://www.cnblogs.com/kikochz/p/12808232.html
Copyright © 2011-2022 走看看