首页>>后端>>SpringBoot->Spring Boot去除参数前后空格和XSS过滤

Spring Boot去除参数前后空格和XSS过滤

时间:2023-11-29 本站 点击:0

去除XSS字符串需要借助工具类 jsoup ,这里jsoup有一点需要注意的是,jsoup的功能可能有点太强大了,能把xss攻击的内容直接过滤掉了不说,也会对英文尖括号<>转义,到接口里面拿到的参数就变成了&lt;&gt;,存库里面的就是转义后的字符串了。取出来的时候需要转一下。

比如前台传的参数传的是: 12<>3<script>alter('11111111')</script>455

过滤处理了后,到后台接口里面就成了:[12&lt;&gt;3455]

如果上面的结果能接受,那么这个工具类就可以用。

引入依赖 jsoup

<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.12.1</version></dependency>

JsoupUtil.java工具类:

importorg.jsoup.Jsoup;importorg.jsoup.nodes.Document;importorg.jsoup.safety.Whitelist;/****@Autherlinmengmeng*@Date2021-08-1915:47**描述:过滤HTML标签中XSS代码*/publicclassJsoupUtil{/***使用自带的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属性*/privatestaticfinalWhitelistwhitelist=Whitelist.basicWithImages();/**配置过滤化参数,不对代码进行格式化*/privatestaticfinalDocument.OutputSettingsoutputSettings=newDocument.OutputSettings().prettyPrint(false);static{//富文本编辑时一些样式是使用style来进行实现的//比如红色字体style="color:red;"//所以需要给所有标签添加style属性whitelist.addAttributes(":all","style");}publicstaticStringclean(Stringcontent){returnJsoup.clean(content,"",whitelist,outputSettings);}}

首先是定义参数过滤器:ParamsFilter 实现 Filter

importjavax.servlet.*;importjavax.servlet.http.HttpServletRequest;importjava.io.IOException;/***Description:参数过滤器**/publicclassParamsFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestarg0,ServletResponsearg1,FilterChainarg2)throwsIOException,ServletException{ParameterRequestWrapperparmsRequest=newParameterRequestWrapper((HttpServletRequest)arg0);arg2.doFilter(parmsRequest,arg1);}@Overridepublicvoidinit(FilterConfigarg0)throwsServletException{}@Overridepublicvoiddestroy(){}}

添加参数过滤配置文件:

importgc.cnnvd.framework.core.filter.ParamsFilter;importorg.springframework.boot.web.servlet.FilterRegistrationBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjavax.servlet.DispatcherType;@ConfigurationpublicclassParameterTrimConfig{/***去除参数头尾空格过滤器*@return*/@BeanpublicFilterRegistrationBeanparmsFilterRegistration(){FilterRegistrationBeanregistration=newFilterRegistrationBean();registration.setDispatcherTypes(DispatcherType.REQUEST);registration.setFilter(newParamsFilter());registration.addUrlPatterns("/*");registration.setName("paramsFilter");registration.setOrder(Integer.MAX_VALUE-1);returnregistration;}}

处理都交给了这货:

importcom.alibaba.fastjson.JSON;importgc.cnnvd.framework.config.converter.JsonValueTrimUtil;importgc.cnnvd.framework.util.JsoupUtil;importorg.apache.commons.io.IOUtils;importorg.apache.commons.lang3.StringUtils;importorg.springframework.http.HttpHeaders;importorg.springframework.http.MediaType;importjavax.servlet.ReadListener;importjavax.servlet.ServletInputStream;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletRequestWrapper;importjava.io.ByteArrayInputStream;importjava.io.IOException;importjava.nio.charset.StandardCharsets;importjava.util.HashMap;importjava.util.Iterator;importjava.util.Map;importjava.util.Set;/****@Autherlinmengmeng*@Date2021-03-2515:47**Description:请求参数的处理,*1.去除参数前后空格*2.过滤XSS非法字符**/publicclassParameterRequestWrapperextendsHttpServletRequestWrapper{privateMap<String,String[]>params=newHashMap<>();publicParameterRequestWrapper(HttpServletRequestrequest){//将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似super(request);//将参数表,赋予给当前的Map以便于持有request中的参数Map<String,String[]>requestMap=request.getParameterMap();this.params.putAll(requestMap);this.modifyParameterValues();}/***重写getInputStream方法post类型的请求参数必须通过流才能获取到值*/@OverridepublicServletInputStreamgetInputStream()throwsIOException{//非json类型,直接返回if(!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))){returnsuper.getInputStream();}//为空,直接返回Stringjson=IOUtils.toString(super.getInputStream(),StandardCharsets.UTF_8);if(StringUtils.isEmpty(json)){returnsuper.getInputStream();}ObjectresultObject=JsonValueTrimUtil.jsonStrTrim(json);//这里处理的是json传参的参数ByteArrayInputStreambis=newByteArrayInputStream(JSON.toJSONString(resultObject).getBytes(StandardCharsets.UTF_8));returnnewCustomServletInputStream(bis);}/***将parameter的值去除空格后重写回去*/publicvoidmodifyParameterValues(){Set<String>set=params.keySet();Iterator<String>it=set.iterator();while(it.hasNext()){Stringkey=it.next();String[]values=params.get(key);values[0]=values[0].trim();values[0]=JsoupUtil.clean(values[0]);//这里处理的是form传参的参数params.put(key,values);}}/***重写getParameter参数从当前类中的map获取*/@OverridepublicStringgetParameter(Stringname){String[]values=params.get(name);if(values==null||values.length==0){returnnull;}returnvalues[0];}/***重写getParameterValues*/@OverridepublicString[]getParameterValues(Stringname){//同上returnparams.get(name);}classCustomServletInputStreamextendsServletInputStream{privateByteArrayInputStreambis;publicCustomServletInputStream(ByteArrayInputStreambis){this.bis=bis;}@OverridepublicbooleanisFinished(){returntrue;}@OverridepublicbooleanisReady(){returntrue;}@OverridepublicvoidsetReadListener(ReadListenerlistener){}@Overridepublicintread()throwsIOException{returnbis.read();}}}

上面form传的参数直接处理了,那么要是JSON传的参数,就要借助下面的工具类了:

importcn.hutool.json.JSONTokener;importcom.alibaba.fastjson.JSONArray;importcom.alibaba.fastjson.JSONObject;importgc.cnnvd.framework.util.JsoupUtil;importorg.apache.commons.lang3.StringUtils;importjava.util.Map;importjava.util.Set;/***@Autherlinmengmeng*@Date2021-03-2515:47*1.去除Json字符串中的属性值前后空格的工具类*2.去除XSS攻击字符*/publicclassJsonValueTrimUtil{publicstaticObjectjsonStrTrim(StringjsonStr){if(StringUtils.isBlank(jsonStr)){return"";}ObjecttypeObject=newJSONTokener(jsonStr).nextValue();if(typeObjectinstanceofcn.hutool.json.JSONObject){returnjsonObjectTrim(JSONObject.parseObject(jsonStr));}if(typeObjectinstanceofcn.hutool.json.JSONArray){returnjsonArrayTrim(JSONArray.parseArray(jsonStr));}jsonStr=JsoupUtil.clean(jsonStr);returnjsonStr.trim();}/***@Description:传入jsonObject去除当中的空格*@paramjsonObject*@return*/publicstaticJSONObjectjsonObjectTrim(JSONObjectjsonObject){//取出jsonObject中的字段的值的空格Set<Map.Entry<String,Object>>entrySets=jsonObject.entrySet();entrySets.forEach(entry->{Objectvalue=entry.getValue();if(value==null){return;}if(valueinstanceofString){StringresultValue=(String)value;if(StringUtils.isNotBlank(resultValue)){resultValue=resultValue.trim();resultValue=JsoupUtil.clean(resultValue);jsonObject.put(entry.getKey(),resultValue);}return;}if(valueinstanceofJSONObject){jsonObject.put(entry.getKey(),jsonObjectTrim((JSONObject)value));return;}if(valueinstanceofJSONArray){jsonObject.put(entry.getKey(),jsonArrayTrim((JSONArray)value));return;}});returnjsonObject;}/***@Description:将jsonarry的jsonObject中的value值去处前后空格*@paramarr*@return*/publicstaticJSONArrayjsonArrayTrim(JSONArrayarr){if(arr!=null&&arr.size()>0){ObjecttempObject=null;for(inti=0;i<arr.size();i++){tempObject=arr.get(i);if(tempObjectinstanceofString){arr.set(i,tempObject);continue;}JSONObjectjsonObject=(JSONObject)arr.get(i);//取出jsonObject中的字段的值的空格jsonObject=jsonObjectTrim(jsonObject);arr.set(i,jsonObject);}}returnarr;}}

测试一下:

importgc.cnnvd.framework.common.api.ApiResult;importgc.cnnvd.framework.log.annotation.OperationLogIgnore;importio.swagger.annotations.Api;importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importio.swagger.annotations.ApiOperation;importlombok.Data;importlombok.experimental.Accessors;importlombok.extern.slf4j.Slf4j;importorg.springframework.validation.annotation.Validated;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjavax.validation.constraints.NotBlank;importjava.io.Serializable;/***@Autherlinmengmeng*@Date2021-03-3016:24*/@Slf4j@RestController@RequestMapping("/tourist")@Api(value="测试游客页面xss",tags={"游客页面xss"})publicclassTouristTestXssController{@PostMapping("/testXssForm")@OperationLogIgnore@ApiOperation(value="测试放开游客页面接口xssForm",notes="测试放开游客页面接口xssForm",response=String.class)publicApiResult<String>testXss(TestXssFormParamtestXssFormParam){log.info("formparamtestStr:[{}]",testXssFormParam.getTestStr());//from不好使returnApiResult.ok(testXssFormParam.getTestStr());}@PostMapping("/testXssJson")@OperationLogIgnore@ApiOperation(value="测试放开游客页面接口xssJson",notes="测试放开游客页面接口xssJson",response=String.class)publicApiResult<String>testXssJson(@Validated@RequestBodyTestXssFormParamtestXssFormParam){log.info("jsonparamtestStr:[{}]",testXssFormParam.getTestStr());returnApiResult.ok(testXssFormParam.getTestStr());}@Data@Accessors(chain=true)@ApiModel(value="testXss参数")publicstaticclassTestXssFormParamimplementsSerializable{privatestaticfinallongserialVersionUID=1L;@NotBlank(message="testStr不能为空")@ApiModelProperty("testStr")privateStringtestStr;}}

上面接口里面的ApiResult为自定义封装的返回数据格式,可以直接修改接口返回类型改为String,就是为了看下后台处理后,返回前台是什么样的。

form传参,过滤成功。

JSON传参,也没毛病。

作者:linmengmeng


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/SpringBoot/348.html