springboot后台xss防御过滤器配置示例

时间:2021-7-5 作者:qvyue

XSS攻击主要是对前端插入可执行脚本来获取用户的敏感信息,对账户安全危害较大。
下面这篇博客对XSS的概念以及攻击类型做了很详细的解释,可以学习参考下。
https://www.cnblogs.com/tugenhua0707/p/10909284.html

XSS对于后台来说,可以在比如上传文件的时候拦截上传请求,把文件地址更改成可执行的javaScript脚本语句插入数据库,这样在页面上查询列表时查出来的可点击的地址链接便是可执行的前端脚本,比如这个接口参数:

{"filePath":"javascript:alert(/xss/)"}

如果地址被修改了成了这样,那点击链接之后前端会执行这段javascript脚本语句。

针对于这种情况,最简单的可以在后台接收参数的时候校验下filePath字段的格式是不是URL就行了。可以用实体类字段里@URL注解

import org.hibernate.validator.constraints.URL;

也可以在过滤器里写一个根据业务的统一的过滤逻辑。

新建一个过滤器类,比如:XssFilter.java

package com.ly.mp.project.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class XssFilter implements Filter {

    FilterConfig filterConfig = null;

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

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

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new XssHttpServletRequestWrapper(
                (HttpServletRequest) request), response);
    }

}

新建XssHttpServletRequestWrapper继承HttpServletRequestWrapper

package com.ly.mp.project.filter;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.springframework.web.util.HtmlUtils;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.ly.mp.project.util.BusinessUtil;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    
    HttpServletRequest orgRequest = null;
    
    private String body;

    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        orgRequest = request;
        body = BusinessUtil.getBodyString(request);
        System.out.println("body==" + body);
    }

    @Override
    public String[] getParameterValues(String parameter) {
        String[] values = super.getParameterValues(parameter);
        if (values == null)
            return null;

        int count = values.length;
        String[] encodedValues = new String[count];
        for (int i = 0; i ':
//              buffer.append(">");
//              break;
//          case '"':
//              buffer.append(""");
//              break;
//          case ''':
//              buffer.append("'");
//              break;
//          case '/':
//              buffer.append("/");
//              break;
//          default:
//              buffer.append(c);
//              break;
            
             case '>':
                 // 全角大于号
                 buffer.append('>');
                 break;
             case '= index + 2) {
                // %3c, %3C
                if (s.charAt(index + 1) == '3' && (s.charAt(index + 2) == 'c' || s.charAt(index + 2) == 'C')) {
                    sb.append('<');
                    return;
                }
                // %3c (0x3c=60)
                if (s.charAt(index + 1) == '6' && s.charAt(index + 2) == '0') {
                    sb.append('<');
                    return;
                }
                // %3e, %3E
                if (s.charAt(index + 1) == '3' && (s.charAt(index + 2) == 'e' || s.charAt(index + 2) == 'E')) {
                    sb.append('>');
                    return;
                }
                // %3e (0x3e=62)
                if (s.charAt(index + 1) == '6' && s.charAt(index + 2) == '2') {
                    sb.append('>');
                    return;
                }
            }
            sb.append(s.charAt(index));
        }
    
    /**
     * 获取最原始的request
     *
     * @return
     */
    public HttpServletRequest getOrgRequest() {
        return orgRequest;
    }
    
    /**
     * 获取最原始的request的静态方法
     *
     * @return
     */
    public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
        if (req instanceof XssHttpServletRequestWrapper) {
            return ((XssHttpServletRequestWrapper) req).getOrgRequest();
        }
        return req;
    }

    
}

这个类中重写了getParameterValues、getParameter、getHeader、getInputStream等方法,在业务层获取参数的时候无非都是调用这几个方法获取,在这几个方法里参数都被cleanXSS这个自定义的方法过滤了,里面的过滤逻辑可根据业务需求自定义,这里做演示替换了一部分符号(不太合理)。

最后把过滤器注入到spring使之生效即可

在启动类里注入或者新建配置类注入

@Bean
    public FilterRegistrationBean myFilterRegistration() {
        FilterRegistrationBean regist = new FilterRegistrationBean(new XssFilter());
        // 过滤全部请求
        regist.addUrlPatterns("/*");//过滤url
        regist.setOrder(1);//过滤器顺序
        return regist;
    }

参考:
https://www.cnblogs.com/tugenhua0707/p/10909284.html
https://www.cnblogs.com/kinome/p/12468421.html

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。