springboot中怎么使用过滤器以及jsoup过滤XSS脚本怎么写
导读:本文共6608.5字符,通常情况下阅读需要22分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: springboot使用过滤器,jsoup过滤XSS脚本背景:略目标:完成request请求中的脚本过滤技术:filter,jsoup,requestWapper1.把可能包含脚本的参数位置分析一下post/put/delete: 请求的参数中,有可能是表单提交、也有可能是使用了@requestBody注解,那么参数就是json格式,位于request的流中。g... ...
目录
(为您整理了一些要点),点击可以直达。springboot使用过滤器,jsoup过滤XSS脚本
背景:略
目标:完成request请求中的脚本过滤
技术:filter,jsoup,requestWapper
1.把可能包含脚本的参数位置分析一下
post
/put
/delete
: 请求的参数中,有可能是表单提交、也有可能是使用了@requestBody注解,那么参数就是json格式,位于request的流中。get
/options
等:可能存在于url参数中,也有可能是表单提交的预请求中,所以一般在能想到的位置都有可能存在,包括header中。
2.分析实现过程
2.1首先要从request请求中将各个需要过滤位置的参数取出来
2.2然后将参数取出来进行过滤
2.3将过滤后的参数重新包装成request传递下去
2.4在这期间,
需要准备好jsoup过滤脚本的工具类;
需要自定义一个过滤器,并且在过滤器中添加匹配条件,如:那些url不需要过滤,那些请求方式必须进行过滤;
对过滤器进行配置,是否开启,设置在整个过滤器链中的位置,设置过滤的白名单或者黑名单
所以就很清晰了我们过滤需要哪些类,哪些配置了
一个filter
一个requestWapper
一个jsoup工具类
一个filter的配置类
2.5进行数据测试
3.代码实现过程
3.1.jsoup依赖:
<!--screenxss--><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.9.2</version></dependency>
3.2jsoup工具类:JsoupUtil
importorg.jsoup.Jsoup;importorg.jsoup.nodes.Document;importorg.jsoup.safety.Whitelist;importjava.io.FileNotFoundException;importjava.io.IOException;/***@Auther:qianshanmuxue*@Date:2019/2/2719:32*@Description:xssIllegallabelfiltering*/publicclassJsoupUtil{privatestaticfinalWhitelistwhitelist=Whitelist.simpleText();//jsoup白名单种类,有四种,每一种针对的标签类型不一样,具体的可以ctrl+左键点击simpleText,在jsoup源码中有响应的注释和标签名单//addmyselfwhitelistlabelprivatestaticfinalDocument.OutputSettingsoutputSettings=newDocument.OutputSettings().prettyPrint(false);static{whitelist.addAttributes(":all","style").addTags("p").addTags("strong");//将自定义标签添加进白名单,除开白名单之外的标签都会被过滤whitelist.preserveRelativeLinks(true);//这个配置的意思的过滤如果找不到成对的标签,就只过滤单个标签,而不用把后面所有的文本都进行过滤。//(之前在这个问题上折腾了很久,当<script>标签只有一个时,会<script>标签后面的数据全部过滤)}publicstaticStringclean(Stringcontent){//过滤方法returnJsoup.clean(content,"",whitelist,outputSettings);}//testmainpublicstaticvoidmain(String[]args)throwsFileNotFoundException,IOException{Stringtext="<ahref=\"http://www.baidu.com/a\"onclick=\"alert(1);\"><strong><p>sss</p></strong></a><script>alert(0);</script>sss";System.out.println(clean(text));}}
3.3request包装类XssHttpServletRequestWrapper
importjava.io.*;importjava.util.*;importjavax.servlet.ReadListener;importjavax.servlet.ServletInputStream;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletRequestWrapper;importcom.xxx.utils.JsoupUtil;importorg.jsoup.nodes.Document;importorg.springframework.util.StringUtils;/***@Auther:qianshanmuxue*@Date:2019/2/2716:24*@Description:requestwapperusetogetrequestparameterandrequestbdoydataandwapperanotherrequest*/publicclassXssHttpServletRequestWrapperextendsHttpServletRequestWrapper{//因为我们需要获取request中的数据,所以需要继承java底层中HttpServletRequestWrapper这个类,重写父类中的某些方法,获取相应位置的参数privateHttpServletRequestorgRequest=null;privatestaticfinalDocument.OutputSettingsoutputSettings=newDocument.OutputSettings().prettyPrint(false);publicXssHttpServletRequestWrapper(HttpServletRequestrequest){super(request);orgRequest=request;}@OverridepublicServletInputStreamgetInputStream()throwsIOException{//getBufferedReaderbr=newBufferedReader(newInputStreamReader(orgRequest.getInputStream()));Stringline=br.readLine();Stringresult="";if(line!=null){result+=clean(line);}returnnewWrappedServletInputStream(newByteArrayInputStream(result.getBytes()));}@OverridepublicStringgetParameter(Stringname){if(("content".equals(name)||name.endsWith("WithHtml"))){returnsuper.getParameter(name);}name=clean(name);Stringvalue=super.getParameter(name);if(!StringUtils.isEmpty(value)){value=clean(value);}returnvalue;}@OverridepublicMapgetParameterMap(){Mapmap=super.getParameterMap();//返回值MapMap<String,String>returnMap=newHashMap<String,String>();Iteratorentries=map.entrySet().iterator();Map.Entryentry;Stringname="";Stringvalue="";while(entries.hasNext()){entry=(Map.Entry)entries.next();name=(String)entry.getKey();ObjectvalueObj=entry.getValue();if(null==valueObj){value="";}elseif(valueObjinstanceofString[]){String[]values=(String[])valueObj;for(inti=0;i<values.length;i++){value=values[i]+",";}value=value.substring(0,value.length()-1);}else{value=valueObj.toString();}returnMap.put(name,clean(value).trim());}returnreturnMap;}@OverridepublicString[]getParameterValues(Stringname){String[]arr=super.getParameterValues(name);if(arr!=null){for(inti=0;i<arr.length;i++){arr[i]=clean(arr[i]);}}returnarr;}/***getorgrequest**@return*/publicHttpServletRequestgetOrgRequest(){returnorgRequest;}/***wapperrequest*/publicstaticHttpServletRequestgetOrgRequest(HttpServletRequestreq){if(reqinstanceofXssHttpServletRequestWrapper){return((XssHttpServletRequestWrapper)req).getOrgRequest();}returnreq;}publicStringclean(Stringcontent){Stringresult=JsoupUtil.clean(content);returnresult;}privateclassWrappedServletInputStreamextendsServletInputStream{publicvoidsetStream(InputStreamstream){this.stream=stream;}privateInputStreamstream;publicWrappedServletInputStream(InputStreamstream){this.stream=stream;}@Overridepublicintread()throwsIOException{returnstream.read();}@OverridepublicbooleanisFinished(){returntrue;}@OverridepublicbooleanisReady(){returntrue;}@OverridepublicvoidsetReadListener(ReadListenerreadListener){}}}
3.4filter-XssFilter
importorg.apache.commons.lang.BooleanUtils;importorg.apache.commons.lang.StringUtils;importjava.io.IOException;importjava.util.ArrayList;importjava.util.List;importjava.util.regex.Matcher;importjava.util.regex.Pattern;importjavax.servlet.Filter;importjavax.servlet.FilterChain;importjavax.servlet.FilterConfig;importjavax.servlet.ServletException;importjavax.servlet.ServletRequest;importjavax.servlet.ServletResponse;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;/***@Auther:qianshanmuxue*@Date:2019/2/2716:25*@Description:*///@WebFilter//@Component在这里可以不用这个注解,以为后面我们会在config中去配置这个filter,在这里只需要实现Filter接口实现相应的方法就okpublicclassXssFilterimplementsFilter{privatestaticbooleanIS_INCLUDE_RICH_TEXT=false;//用于接收配置中的参数,决定这个过滤器是否开启publicList<String>excludes=newArrayList<String>();//用于接收配置中的参数,决定哪些是不需要过滤的url(在这里,也可以修改handleExcludeURL()方法中相应的代码,使其变更为只需要过滤的url)@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{HttpServletRequestreq=(HttpServletRequest)request;HttpServletResponseresp=(HttpServletResponse)response;if(handleExcludeURL(req,resp)){chain.doFilter(request,response);return;}XssHttpServletRequestWrapperxssRequest=newXssHttpServletRequestWrapper((HttpServletRequest)request);chain.doFilter(xssRequest,response);}/***此方法是决定对当前url是否执行过滤,*在这里没有使用请求方法(post/put)来匹配,因为在本项目中使用url匹配更适合(因为get和其他请求方式也需要进行过滤),如果你有兴趣可以把这个方法更改为匹配请求方法进行过滤**/privatebooleanhandleExcludeURL(HttpServletRequestrequest,HttpServletResponseresponse){if((excludes==null||excludes.isEmpty())&&IS_INCLUDE_RICH_TEXT){returnfalse;}Stringurl=request.getServletPath();for(Stringpattern:excludes){Patternp=Pattern.compile("^"+pattern);Matcherm=p.matcher(url);if(m.find()){returntrue;}}returnfalse;}/***过滤器初始化,从配置类中获取参数,用于初始化两个参数(是否开启,排除指定的urllist)**/@Overridepublicvoidinit(FilterConfigarg0)throwsServletException{StringisIncludeRichText=arg0.getInitParameter("isIncludeRichText");if(StringUtils.isNotBlank(isIncludeRichText)){IS_INCLUDE_RICH_TEXT=BooleanUtils.toBoolean(isIncludeRichText);}Stringtemp=arg0.getInitParameter("excludes");if(temp!=null){String[]url=temp.split(",");for(inti=0;url!=null&&i<url.length;i++){excludes.add(url[i]);}}}@Overridepublicvoiddestroy(){}}
3.5filter的配置类:XssConfig
importcom.xxx.filter.XssFilter;importcom.google.common.collect.Maps;importorg.springframework.boot.web.servlet.FilterRegistrationBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.util.Map;/***@Auther:qianshanmuxue*@Date:2019/2/2716:49*@Description:xssfilterconfig*/@ConfigurationpublicclassXssConfig{@BeanpublicFilterRegistrationBeanxssFilterRegistrationBean(){FilterRegistrationBeanfilterRegistrationBean=newFilterRegistrationBean();filterRegistrationBean.setFilter(newXssFilter());filterRegistrationBean.setOrder(1);//filterorder,setitfirstfilterRegistrationBean.setEnabled(true);filterRegistrationBean.addUrlPatterns("/*");//setfilterallurlmappingMap<String,String>initParameters=Maps.newHashMap();initParameters.put("excludes","/oauth/token");///whitelisturlinitParameters.put("isIncludeRichText","true");//enableordisablefilterRegistrationBean.setInitParameters(initParameters);returnfilterRegistrationBean;}}
调试截图:
请求:
程序截图:
运行结果:
可以看到body中 的脚本已经被过滤了,
然后其他的截图我就不发了,还有一种思路就是在过滤器中把字符转义。
感谢luckpet大佬的提示
1 BufferedReader 使用完需要关闭 ;
2 对于一些拿postman等工具的朋友,拼接json的话会有换行 这里result += clean(line); 需要改成: while((line = br.readLine()) != null){ if (line != null) { result += line; } }
使用jsoup防止XSS攻击
前阵子项目国测后,打开一个项目页面,莫名其妙弹出xss,搜了全局也没找到alert("xss"),问了一下项目经理,原来是国测做防注入的时候,在添加数据的时候做的,一脸懵逼。
查了一下资料,以前做项目的时候都没想到这个问题,如果保存一段script脚本,查数据的时候,这段脚本就会被执行,这东西后果挺严重啊,如果是在桌面外弹框,执行个挖矿脚本,这玩意不得了啊,厉害,长知识了。。。
<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.11.3</version></dependency>
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
springboot中怎么使用过滤器以及jsoup过滤XSS脚本怎么写的详细内容,希望对您有所帮助,信息来源于网络。