Spring boot 过滤器实现防XSS攻击

文章目录

背景

框架中添加xss攻击过滤器类,防止脚本攻击,能够做到引入包即可使用。

参考资料

这里主要参考renren-fast官方提供的开源项目的xss攻击进行改造。

参考io/renren/common/xss包下面类

三方包 hutool-http参考博客api里面提供了xss所需的标签替换等功能

上代码

过滤器配置

/**
 * Filter配置
 *
 * @author lirui
 */
@Configuration
public class FilterConfig {

    /**
     * 注册过滤器
     *
     * @param url 提供可不拦截接口
     *            实现配置不过滤部分接口,部分接口需要不做过滤
     * @return
     */
    @Bean
    public FilterRegistrationBean xssFilterRegistration(XssIgnoreFilterUrl url) {
        FilterRegistrationBean registration = getFilterRegistrationBean(url);
        return registration;
    }

    private FilterRegistrationBean getFilterRegistrationBean(XssIgnoreFilterUrl url) {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        //指定发起请求时过滤
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.setFilter(new XssFilter(Objects.isNull(url) ? null : url.getUrls()));
        //默认所有接口
        registration.addUrlPatterns("/*");
        registration.setName("xssFilter");
        //设置最后执行,防止有其他过滤器对值需要修改等操作,保证最后过滤字符即可
        registration.setOrder(Integer.MAX_VALUE);
        return registration;
    }
}

可配置不过滤地址

/**
 * xss忽略过滤地址
 *
 * @author LiRui
 * @version 1.0
 */
@Configuration
@ConfigurationProperties(prefix = "xss.ignore")
public class XssIgnoreFilterUrl {
    private Set<String> urls;

    public Set<String> getUrls() {
        return urls;
    }

    public void setUrls(Set<String> urls) {
        this.urls = urls;
    }
}

//yml配置
xss:
  ignore:
    urls:
      - /xss/form

主要过滤器代码

/**
 * XSS过滤
 *
 * @author lirui
 */
public class XssFilter implements Filter {

    private Set<String> excludedUris;

    public XssFilter() {
    }

    public XssFilter(Set<String> excludedUris) {
        this.excludedUris = excludedUris;
    }

    /**
     * 是否排除
     *
     * @param uri
     * @return
     */
    private boolean isExcludedUri(String uri) {
        if (CollectionUtils.isEmpty(excludedUris)) {
            return false;
        }
        for (String ex : excludedUris) {
            if (match(ex, uri)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 地址匹配
     *
     * @param patternPath
     * @param requestPath
     * @return
     */
    public static boolean match(String patternPath, String requestPath) {
        if (StringUtils.isEmpty(patternPath) || StringUtils.isEmpty(requestPath)) {
            return false;
        }
        PathMatcher matcher = new AntPathMatcher();
        return matcher.match(patternPath, requestPath);
    }


    @Override
    public void init(FilterConfig config) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        //可配置多个字符串过滤
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
                (HttpServletRequest) request, new HTMLFilter());
        String url = xssRequest.getServletPath();
        if (isExcludedUri(url)) {
            chain.doFilter(request, response);
            return;
        }
        chain.doFilter(xssRequest, response);
    }

    @Override
    public void destroy() {
    }
}

这里注意match方法,用的Spring包的地址匹配工具,通过匹配地址是否需要过滤

xss具体过滤规则

代码较多我就不贴,最后我会上传到gtee仓库。主要注意,renren-fast中如果存在<或者> 单个的,就会自动在求前面或者最后面进行添加另一符号。在过滤时就会删除前面或者后面内容,具体的可以自己试试renrenfast的代码,内容用<或者>一个符号加内容测试就明白了我的意思。 源代码中我将这段代码注释:

            //自动补充<,> 注释允许传递<>符号
//            s = regexReplace(P_BODY_TO_END, "<$1>", s);
//            s = regexReplace(P_XML_CONTENT, "$1<$2", s);

遇到这种标签,源码中返回的是xxxx,根据业务需求直接返回“”.使用hutool三方包调整代码(仓库中的代码没修改,需要同样需求的自己copy):

return HtmlUtil.cleanHtmlTag(HtmlKit.getTextFromHtml(s));
//getTextFromHtml方法源码
  public static String getTextFromHtml(String htmlStr) {
        if (htmlStr == null) {
            return "";
        } else {
            htmlStr = delHtmlLabel(htmlStr);
            htmlStr = htmlStr.replaceAll("&nbsp;", "");
            return htmlStr;
        }
    }

注意扫描该包(或者加starter也行)

@SpringBootApplication(scanBasePackages = {“com.web”})

关于富文本框

开放不做过滤接口配置主要是考虑富文本框的问题,看了很多文章其实主要是处理js脚本,尽量在前端做一次符号转义,然后后端xss攻击过滤器还是需要开启保证安全。

gitee代码仓库

仓库地址

common是过滤器相关源码,web为自己测试的代码

上一篇:RAR registration data


下一篇:Android闹钟 AlarmManager的使用