SpringBoot过滤XSS脚本攻击

作者: 1ff5a98e5398 | 来源:发表于2018-10-06 23:21 被阅读1次

    前排提示

        源码在最后

    XSS攻击是什么

        XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。
        简而言之,就是作恶用户通过表单提交一些前端代码,如果不做处理的话,这些前端代码将会在展示的时候被浏览器执行。

    如何避免XSS攻击

        这里我根据个人经验做一个总结,可能经验也有不足之处。我个人解决XSS攻击是通过后端转译的办法来解决的。在实际项目中,react、vue等前后端完全分离的框架似乎已经帮我们处理了XSS脚本,这个本人对于前端略懂皮毛而已,这里就不做探讨了。下面主要实现以后端做XSS过滤。

    代码实现

        对于过滤XSS脚本的代码,通过搜索引擎可以搜索到很多,但似乎都不是那么全面。基本上都是只能过滤querystring类型的入参,而不能过滤json类型的入参。其实,在现在的开发中,更多的是使用json类型做数据交互。下面就直接贴代码了:

    XssAndSqlHttpServletRequestWrapper.java

    package com.loger.filter;
    
    import org.apache.commons.lang3.StringUtils;
    import org.apache.commons.text.StringEscapeUtils;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    
    /**
     * @author Loger
     * 防止XSS攻击
     */
    public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {
    
        private HttpServletRequest request;
    
        public XssAndSqlHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
            this.request = request;
        }
    
        @Override
        public String getParameter(String name) {
            String value = request.getParameter(name);
            if (!StringUtils.isEmpty(value)) {
                value = StringEscapeUtils.escapeHtml4(value);
            }
            return value;
        }
    
        @Override
        public String[] getParameterValues(String name) {
            String[] parameterValues = super.getParameterValues(name);
            if (parameterValues == null) {
                return null;
            }
            for (int i = 0; i < parameterValues.length; i++) {
                String value = parameterValues[i];
                parameterValues[i] = StringEscapeUtils.escapeHtml4(value);
            }
            return parameterValues;
        }
    
    }
    

        简单讲解下,这里重写了两个方法:getParameter和getParameterValues,getParameter方法是直接通过request获得querystring类型的入参调用的方法。如果是通过springMVC注解类型来获得参数的话,走的是getParameterValues的方法。
        StringEscapeUtils.escapeHtml4这个方法来自Apache的工具类,maven坐标如下:

    <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-text</artifactId>
          <version>1.4</version>
    </dependency>
    

        过滤的代码写完了,下面就是在一个filter中应用该代码。

    XssFilter.java

    package com.loger.filter;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Primary;
    import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    
    /**
     * @author Loger
     */
    @WebFilter
    @Component
    public class XssFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) request;
            XssAndSqlHttpServletRequestWrapper xssRequestWrapper = new XssAndSqlHttpServletRequestWrapper(req);
            chain.doFilter(xssRequestWrapper, response);
        }
    
        @Override
        public void destroy() {
    
        }
    
         /**
         * 过滤json类型的
         * @param builder
         * @return
         */
        @Bean
        @Primary
        public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
            //解析器
            ObjectMapper objectMapper = builder.createXmlMapper(false).build();
            //注册xss解析器
            SimpleModule xssModule = new SimpleModule("XssStringJsonSerializer");
            xssModule.addSerializer(new XssStringJsonSerializer());
            objectMapper.registerModule(xssModule);
            //返回
            return objectMapper;
        }
    
    }
    

        就这样,过滤querystring类型的代码已经完成(xssObjectMapper这个是后面过滤json类型才用到的)。下面来实现过滤json类型的代码:

    XssStringJsonSerializer.java

    package com.loger.filter;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import org.apache.commons.text.StringEscapeUtils;
    
    import java.io.IOException;
    
    public class XssStringJsonSerializer extends JsonSerializer<String> {
    
        @Override
        public Class<String> handledType() {
            return String.class;
        }
    
        @Override
        public void serialize(String value, JsonGenerator jsonGenerator,
                              SerializerProvider serializerProvider) throws IOException {
            if (value != null) {
                String encodedValue = StringEscapeUtils.escapeHtml4(value);
                jsonGenerator.writeString(encodedValue);
            }
        }
    
    }
    
    

        这里通过修改SpringMVC的json序列化来达到过滤xss的目的的。其实也可以通过第一种方法,重写getInputStream方法来实现,但由于得到的是ServletInputStream,不太好处理。(通过json类型传参会走getInputStream方法,通过重写该方法打印输出可以证明)
        下面可以通过几个例子验证下是否成功:
        简单写一个controller

    TestController.java

    package com.loger.controller;
    
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    
    /**
     * @author Loger
     * Date: 2018-10-05
     * TIme: 19:14
     * Description :
     */
    @RestController
    @RequestMapping(value = "/test")
    public class TestController {
    
        @PostMapping(value = "/xss")
        public Object test(String name) {
            System.out.println(name);
            return name;
        }
    
        @PostMapping(value = "/json")
        public Object testJSON(@RequestBody Param param) {
            return param;
        }
    
        @GetMapping(value = "/query")
        public Object testQuery(String q){
            return q;
        }
    
        @PostMapping(value = "/upload")
        public Object upload(MultipartFile file){
            System.out.println(file.getOriginalFilename());
            return "OK";
        }
    
    }
    

        下面通过postman测试下效果:


    图片.png 图片.png 图片.png

    git地址:https://github.com/logerchen/springboot-xss.git

    相关文章

      网友评论

        本文标题:SpringBoot过滤XSS脚本攻击

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