SpringBoot整合XssFilter,Jsoup等实现请求参数的过滤,处理Xss攻击及sql注入,以下是涉及的主要类:
Springboot中会使用FilterRegistrationBean来注册Filter,Filter是Servlet规范里面的,属于容器范围,Springboot中没有web.xml,那Springboot中,不用管Filter是如何交给Servlet容器,只见FilterRegistrationBean的如下继承图,即可知道。(现在框架很多,各个都要穷究底层,可能时间不允许?可能项目不允许?……只要熟悉了,慢慢就会知道“Filter是如何交给Servlet容器”的潜规则)
大致原理:有的方法可能同时需要多个filter依次对其进行过滤,这时候便需要对filter的执行进行优先级的排序。如下:
1、新建一个配置文件WEBConfig.java,
2、先生成一个过滤器的bean,
3、再把过滤器的bean注入到FilterRegistrationBean中,并设置一些属性,过滤的url,执行的顺序之类的(order的数值越小,优先级越高)即可。
1、在springboot 中,依赖FilterRegistrationBean 这个类,实现Filter【javax.servlet.Filter】接口,实现Filter方法
2、添加 @Configuration 注解,将自定义Filter加入过滤链
package com.AAAAAAAAAAAA.common.config;
import com.AAAAAAAAAAAA.common.interceptor.XSRFHandlerInterceptor;
import com.AAAAAAAAAAAA.common.xss.XssFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
@Configuration
@SuppressWarnings("unchecked")
public class WebConfig {
/**
* XssFilter Bean
*/
@Bean
public FilterRegistrationBean xssFilterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new XssFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.setEnabled(true);
filterRegistrationBean.addUrlPatterns("/*");
Map initParameters = new HashMap<>();
initParameters.put("excludes", "/favicon.ico,/img/*,/js/*,/css/*");
initParameters.put("isIncludeRichText", "true");
filterRegistrationBean.setInitParameters(initParameters);
return filterRegistrationBean;
}
@Bean
public ObjectMapper getObjectMapper(FebsProperties febsProperties) {
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat(febsProperties.getTimeFormat()));
return mapper;
}
@Bean //将组件注册在容器
public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
//注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//super.addInterceptors(registry);
//静态资源; *.css , *.js
//SpringBoot已经做好了静态资源映射
registry.addInterceptor(new XSRFHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/static/**","/css/**", "/js/**", "/fonts/**","/index","/error",
"/img/**", "/druid/**", "/user/regist", "/gifCode", "/*.gif", "/", "/actuator/**", "/test/**");
// .excludePathPatterns("/addSuggest","/traffic/login","/traffic/logout","/logout","/css/**","/js/**","/fonts/**",
// "/img/**","/druid/**","/user/regist","/gifCode","/*.gif","/","/actuator/**","/test/**");
}
};
return adapter;
}
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
filterRegistrationBean.setFilter(new XssFilter());
//过滤应用程序中所有资源,当前应用程序根下的所有文件包括多级子目录下的所有文件,注意这里*前有“/”
registration.addUrlPatterns("/*");
//过滤指定的类型文件资源, 当前应用程序根目录下的所有html文件,注意:*.html前没有“/”,否则错误
registration.addUrlPatterns(".html");
//过滤指定的目录下的所有文件,当前应用程序根目录下的folder_name子目录(可以是多级子目录)下所有文件
registration.addUrlPatterns("/folder_name/*");
//过滤指定文件
registration.addUrlPatterns("/index.html");
webMvcConfigurerAdapter被不被推荐使用,推荐使用WebMvcConfigurer
友情链接:https://www.cnblogs.com/telwanggs/p/10802011.html https://blog.csdn.net/weixin_42184538/article/details/85266822
package com.AAAAAAAAAAAA.common.xss;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Xss攻击拦截器
*
*/
public class XssFilter implements Filter {
private static Logger logger = LoggerFactory.getLogger(XssFilter.class);
// 是否过滤富文本内容
private boolean flag = false;
private List excludes = new ArrayList<>();
@Override
public void init(FilterConfig filterConfig) {
logger.info("------------ xss filter init ------------");
String isIncludeRichText = filterConfig.getInitParameter("isIncludeRichText");
if (StringUtils.isNotBlank(isIncludeRichText)) {
flag = BooleanUtils.toBoolean(isIncludeRichText);
}
String temp = filterConfig.getInitParameter("excludes");
if (temp != null) {
String[] url = temp.split(",");
excludes.addAll(Arrays.asList(url));
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if (handleExcludeURL(req)) {
chain.doFilter(request, response);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request,
flag);
chain.doFilter(xssRequest, response);
}
@Override
public void destroy() {
// do nothing
}
private boolean handleExcludeURL(HttpServletRequest request) {
if (excludes == null || excludes.isEmpty()) {
return false;
}
String url = request.getServletPath();
return excludes.stream().map(pattern -> Pattern.compile("^" + pattern)).map(p -> p.matcher(url)).anyMatch(Matcher::find);
}
}
XssFilter根据WebConfig中的isIncludeRichText的布尔值,进行是否拦截富文本内容,及excludes内容的过滤和其他请求的传递!,该类引入了XssHttpServletRequestWrapper包装类。
package com.AAAAAAAAAAAA.common.xss;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.lang3.StringUtils;
import com.AAAAAAAAAAAA.common.util.JsoupUtil;
import java.util.stream.IntStream;
/**
* Jsoup过滤http请求,防止Xss攻击
*
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest orgRequest;
private boolean isIncludeRichText;
XssHttpServletRequestWrapper(HttpServletRequest request, boolean isIncludeRichText) {
super(request);
orgRequest = request;
this.isIncludeRichText = isIncludeRichText;
}
/**
* 覆盖getParameter方法,将参数名和参数值都做xss过滤
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
@Override
public String getParameter(String name) {
if (("content".equals(name) || name.endsWith("WithHtml")) && !isIncludeRichText) {
return super.getParameter(name);
}
name = JsoupUtil.clean(name);
String value = super.getParameter(name);
if (StringUtils.isNotBlank(value)) {
value = JsoupUtil.clean(value);
}
return value;
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取
* getHeaderNames 也可能需要覆盖
*/
@Override
public String getHeader(String name) {
name = JsoupUtil.clean(name);
String value = super.getHeader(name);
if (StringUtils.isNotBlank(value)) {
value = JsoupUtil.clean(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] arr = super.getParameterValues(name);
if (arr != null) {
IntStream.range(0, arr.length).forEach(i -> arr[i] = JsoupUtil.clean(arr[i]));
}
return arr;
}
/**
* 获取原始的request
*/
private HttpServletRequest getOrgRequest() {
return orgRequest;
}
/**
* 获取原始的request的静态方法
*/
public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
if (req instanceof XssHttpServletRequestWrapper) {
return ((XssHttpServletRequestWrapper) req).getOrgRequest();
}
return req;
}
}
XssHttpServletRequestWrapper为包装类,将参数名和参数值都做xss过滤。采用Jsoup过滤http请求,防止Xss攻击,将容易引起xss漏洞的半角字符直接替换成全角字符等。
package com.AAAAAAAAAAAA.common.util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Whitelist;
/**
* Xss过滤工具
*
*/
public class JsoupUtil {
protected JsoupUtil(){
}
/**
* 使用自带的basicWithImages 白名单
* 允许的便签有a,b,blockquote,br,cite,code,dd,dl,dt,em,i,li,ol,p,pre,q,small,span,
* strike,strong,sub,sup,u,ul,img
* 以及a标签的href,img标签的src,align,alt,height,width,title属性
*/
private static final Whitelist whitelist = Whitelist.basicWithImages();
/*
* 配置过滤化参数,不对代码进行格式化
*/
private static final Document.OutputSettings outputSettings = new Document.OutputSettings().prettyPrint(false);
static {
/*
* 富文本编辑时一些样式是使用style来进行实现的 比如红色字体 style="color:red;" 所以需要给所有标签添加style属性
*/
whitelist.addAttributes(":all", "style");
}
public static String clean(String content) {
return Jsoup.clean(content, "", whitelist, outputSettings);
}
}
JsoupUtil.java使用自带的basicWithImages 白名单等,过滤掉所有的html标签,拦截XSS
在webconfig.java中,引入此类。进行项目的请求信息进行拦截传递,及参数列表中的sha摘要和后台生成的sha摘要进行比较,sha摘要 匹配完成 没有被篡改,进行放行
具体代码
package com.AAAAAAAAAAAA.common.interceptor;
import com.AAAAAAAAAAAA.common.domain.ResponseBo;
import com.AAAAAAAAAAAA.traffic.util.SignUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @Auther: 阿啄debugIT
* @Date: 2019/12/26
* @Description:
*/
public class XSRFHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("============进入xsrf拦截器==================");
System.out.println(request.getMethod() + "请求地址: " + request.getRequestURL());
//获取request中的请求参数
Map map = request.getParameterMap();
Map paramMap = new HashMap<>();
Iterator iter = map.entrySet().iterator();
// 前台参数的sha摘要
String shakey = "";
// 获取所有的参数
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String key = (String) entry.getKey();
String[] val = (String[]) entry.getValue();
if (val.length > 0) {
if ("token".equals(key)) {
shakey = val[0];
} else {
if ("/traffic/login".equals(request.getServletPath())) {
val[0] = val[0].replaceAll(" ", "+");
}
paramMap.put(key, val[0]);
}
}
System.out.println("key: " + key + "; value: " + val[0]);
}
System.out.println("前端传过来token: " + shakey);
// 后台通过除了 key之后所有的参数 生成sha摘要
String xsfrShaKey = SignUtil.SHA1(paramMap);
System.out.println("后台生成的token: " + xsfrShaKey);
// 参数列表中的sha摘要和后台生成的sha摘要进行比较
if (!shakey.equals(xsfrShaKey)) {
// sha摘要 匹配完成 没有被篡改,进行放行
return true;
} else {
render(response);
return false;
}
// return true;
}
private void render(HttpServletResponse response) throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
// Result result = new Result(500, "", "请求异常");
ResponseBo result=ResponseBo.error("请检查您输入的信息是否存在敏感信息,或者操作是否非法");
String str = JSON.toJSONString(result);
out.write(str.getBytes("UTF-8"));
out.flush();
out.close();
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object Objecthandler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
能力与精力有限,难免有误,敬请指正,谢谢!
以上所有涉及代码https://download.csdn.net/download/as4589sd/12144926