SpringBoot如何防止XSS攻击

一、什么是XSS漏洞

XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。

二、如何避免XSS攻击

在SpringBoot框架里,可以通过新建过滤器的方式过滤所有的请求参数,这样代码改动范围比较小且对业务模块的侵入性比较低。

环境和框架

  1. 开发语言:Java
  2. 框架: SpringBoot:2.1.17.RELEASE
  3. 依赖组件: hutool-all:5.0.3

过滤html标记

1、创建XssHttpServletRequestWrapper

@Slf4j
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {


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

    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (StringUtils.isEmpty(value)) {
            return value;
        }
        // 过滤html标记
        return HtmlUtil.filter(value);
    }

    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (StringUtils.isEmpty(value)) {
            return value;
        }
        // 过滤html标记
        return  HtmlUtil.filter(value);
    }
	
    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if(values == null) {
            return null;
        }
        for (int i = 0; i < values.length; i++) {
            if (StringUtils.isEmpty(values[i])) {
                values[i] = values[i];
            } else {
            	// 过滤html标记
                values[i] = HtmlUtil.filter(values[i]);
            }
        }
        return values;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
    	// 请求方法为POST时会触发这个方法
        return getInputStreamWithXSSFilter();
    }


    public ServletInputStream getInputStreamWithXSSFilter() throws IOException {
    	// 从inputStream读取字符串
        InputStream in = super.getInputStream();
        StringBuffer body = new StringBuffer();
        InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
        BufferedReader buffer = new BufferedReader(reader);
        String line = buffer.readLine();
        while (line != null) {
            body.append(line);
            line = buffer.readLine();
        }
        buffer.close();
        reader.close();
        in.close();

		// 使用hutool的Html工具类过滤
        String str = HtmlUtil.filter(body.toString());
        // 双引号不需要过滤因此替换回原来的符号
        str = str.replace("&quot;","\"");
        // 因为request里面的inputStream已经读取过,指针指向结尾重新读取会发生异常, 
        // 而且过滤后的字符串可能和之前的字符串不同,因此将过滤后的字符串重新转成inputStream返回
        final ByteArrayInputStream bain = new ByteArrayInputStream(str.getBytes());
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bain.read();
            }

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

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

            @Override
            public void setReadListener(ReadListener listener) {
            }
        };
    }
}

2、创建过滤器XssFilter

@WebFilter(urlPatterns = "/*", filterName = "xssFilter")
public class XssFilter implements Filter {
    private FilterConfig filterConfig = null;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        filterChain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
    }

    @Override
    public void destroy() {
        this.filterConfig = null;
    }
}

3、创建XSSFilterFilterConfig配置过滤器

@Configuration
public class XSSFilterConfig {
 
    /**
     * 注册xxs过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean xxsFilterRegistration(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new XssFilter());
        // 设置过滤器url匹配规则,也可以在 Filter 的实现类的 doFilter 里自定义更复杂路由匹配规则
        filterRegistrationBean.addUrlPatterns("/*");
        // 设置过滤器名称
        filterRegistrationBean.setName("XssFilter");
        // 设置过滤器优先级
        filterRegistrationBean.setOrder(99);
        return filterRegistrationBean;
    } 
}

XSSFilterFilterConfig的作用是通过@Bean注解的方式注册过滤器。

SpringBoot使用的是 ApplicationFilterChain 这个类管理和链式按顺序执行过滤器

public final class ApplicationFilterChain implements FilterChain {
...

添加的过滤器的实例都保存在 ApplicationFilterChain 的 filters 里面,每当有新的请求进入就会依次经过 filters 里的过滤器

在这里插入图片描述
主要代码来源于网络,主要是对 getInputStream 方法里存在的问题尝试进行修改

参考: https://blog.csdn.net/Sunshine_zjh/article/details/118054764
git仓库: https://gitee.com/lai-xuxiang/csrf-xss-demo

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值