java xssprotect使用_java 拦截器解决xss攻击

一、xss攻击

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。

简单说就是说,通过在输入框输入一些js代码,如在账号密码输入框中输入

或者

这样点击提交的时候就会触发alert弹窗,分别弹出 xss  和 @@ 的内容,这里只是做个简单的演示,弹了个窗口,还能存储病毒下载地址到服务端,进入的时候自动下载,或者修改你的cookie啥的,这里感兴趣可以百度查查xss攻击。

二、如何防御

解决思路对用户提交表单的参数进行转移,如把< 转换为 <  把 > 转换为 &rt;

java有很多的过滤工具类

commons-lang

commons-lang

2.6

然后通过下面的代码即可过滤

StringEscapeUtils.escapeHtml(string);

底层也是将一切标签进行转移,达到js调用不生效的作用。

这里使用的是filter过请求进行拦截处理。

过滤的内容报过get请求的参数、对象, post形式body中的参数

1)添加xss过滤器

XssgFilter

com.train.web.filter.XssFilter

XssgFilter

/*

这里过滤了所有的请求,其中XssFilter是我们自己过滤器

2)添加自己的过滤器,

import javax.servlet.*;importjavax.servlet.http.HttpServletRequest;importjava.io.IOException;public class XssFilter implementsFilter {

@Overridepublic void init(FilterConfig filterConfig) throwsServletException {

}

@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throwsIOException, ServletException {

XssHttpServletRequestWrapper req=newXssHttpServletRequestWrapper((HttpServletRequest)servletRequest);

filterChain.doFilter(req,servletResponse);

}

@Overridepublic voiddestroy() {

}

}

3)定义自己的http包装类

public class XssHttpServletRequestWrapper extendsHttpServletRequestWrapper {boolean isUpData = false;//判断是否是上传 上传忽略

publicXssHttpServletRequestWrapper(HttpServletRequest servletRequest) {super(servletRequest);

String contentType=servletRequest.getContentType ();if (null !=contentType)

isUpData=contentType.startsWith ("multipart");

}

@OverridepublicString[] getParameterValues(String parameter) {

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

}int count =values.length;

String[] encodedValues= newString[count];for (int i = 0; i < count; i++) {

encodedValues[i]=cleanXSS(values[i]);

}returnencodedValues;

}

@OverridepublicString getParameter(String parameter) {

String value= super.getParameter(parameter);if (value == null) {return null;

}returncleanXSS(value);

}/*** 获取request的属性时,做xss过滤*/@OverridepublicObject getAttribute(String name) {

Object value= super.getAttribute(name);if (null != value && value instanceofString) {

value=cleanXSS((String) value);

}returnvalue;

}

@OverridepublicString getHeader(String name) {

String value= super.getHeader(name);if (value == null)return null;returncleanXSS(value);

}private staticString cleanXSS(String value) {

value= value.replaceAll("", ">");

value= value.replaceAll("%3C", "<").replaceAll("%3E", ">");

value= value.replaceAll("\\(", "(").replaceAll("\\)", ")");

value= value.replaceAll("%28", "(").replaceAll("%29", ")");

value= value.replaceAll("'", "'");

value= value.replaceAll("eval\\((.*)\\)", "");

value= value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");

value= value.replaceAll("script", "");returnvalue;

}

@Overridepublic ServletInputStream getInputStream () throwsIOException {if(isUpData){return super.getInputStream ();

}else{final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ());return newServletInputStream() {

@Overridepublic int read() throwsIOException {returnbais.read();

}

@Overridepublic booleanisFinished() {return false;

}

@Overridepublic booleanisReady() {return false;

}

@Overridepublic voidsetReadListener(ReadListener readListener) { }

};

}

}publicString inputHandlers(ServletInputStream servletInputStream){

StringBuilder sb= newStringBuilder();

BufferedReader reader= null;try{

reader= new BufferedReader(new InputStreamReader (servletInputStream, Charset.forName("UTF-8")));

String line= "";while ((line = reader.readLine()) != null) {

sb.append(line);

}

}catch(IOException e) {

e.printStackTrace();

}finally{if (servletInputStream != null) {try{

servletInputStream.close();

}catch(IOException e) {

e.printStackTrace();

}

}if (reader != null) {try{

reader.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}returncleanXSS(sb.toString ());

}

}

但是这里有个问题,假如这里还有一些特殊的需求,有些html标签是希望在前端能显示的,前端通过一些已经防止了xss攻击的富文本控件输入信息,后台不希望将这些信息转义

三、添加一些额外的内容

1)希望能动态的开关

2)期待部分接口的接口的参数是能存在标签的

添加一个xss开关的控制类, 这里使用了配置中心

importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;

@Componentpublic classXSSFilterConfigUtil {public staticBoolean openXssProtect;public staticBoolean getOpenXssProtect() {return openXssProtect == null ? false: openXssProtect;

}

@Value("${open.xss.protect}")public voidsetOpenXssProtect(Boolean openXssProtect) {

XSSFilterConfigUtil.openXssProtect=openXssProtect;

}

}

注意的是:

1. @Value无法为静态属性注入值,所以需要添加set方法为其注入值;

2. 工具类必须添加@Component或者@Service注解,否则@Value不起作用。

静态方法中注入了值以后,Filter中就可以直接使用了。

修改上面的http包装类,这里不对" 进行过滤,过滤的话,会把json的""个去除,使用@RequestBody没办法解析成为一个正常的对象

importcom.alibaba.fastjson.JSONObject;importcom.train.service.impl.XSSFilterConfigUtil;importorg.apache.commons.lang.StringUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjavax.servlet.ServletInputStream;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletRequestWrapper;importjava.io.BufferedReader;importjava.io.ByteArrayInputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjava.nio.charset.Charset;importjava.util.HashMap;importjava.util.Map;importjava.util.regex.Matcher;importjava.util.regex.Pattern;/*** 防护http处理

* 1.过滤xss*/

public class XssHttpServletRequestWrapper extendsHttpServletRequestWrapper {private static final Logger LOGGER = LoggerFactory.getLogger(XssHttpServletRequestWrapper.class);boolean isUpData = false;//判断是否是上传 上传忽略//不期待被过滤的的链接和字段(管理后台使用了富文本,希望有可编辑的内容)

HashMap doNotFilterURLAndParamMap = new HashMap() {

{

put("/api/v2/group/manage", "description");

put("/api/v1/sendNews", "content");

}

};/*** Constructs a request object wrapping the given request.

*

*@paramrequest The request to wrap

*@throwsIllegalArgumentException if the request is null*/

publicXssHttpServletRequestWrapper(HttpServletRequest request) {super(request);

String contentType=request.getContentType ();if (null !=contentType)

isUpData=contentType.startsWith ("multipart");

}/*** 过滤单个参数

*@paramname

*@return

*/@OverridepublicString getParameter(String name) {

String parameter= super.getParameter(name);if(StringUtils.isNotBlank(parameter) &&XSSFilterConfigUtil.getOpenXssProtect()){//这里使用的阿帕奇的common-lang3中的转义html方法,也可以自己实现,

String escapeParameter = this.cleanXSS(parameter);returnescapeParameter;

}returnparameter;

}/*** 过滤实体的每个参数

*@paramname

*@return

*/@OverridepublicString[] getParameterValues(String name) {

String[] parameterValues= super.getParameterValues(name);if (parameterValues == null) {return null;

}if(XSSFilterConfigUtil.getOpenXssProtect()) {for (int i = 0; i < parameterValues.length; ++i) {

String value=parameterValues[i];

parameterValues[i]= this.cleanXSS(value);

}

}returnparameterValues;

}/*** 处理@RequestBody的形式传入的json数据

*@return*@throwsIOException*/@Overridepublic ServletInputStream getInputStream () throwsIOException {if(!XSSFilterConfigUtil.getOpenXssProtect()) {return super.getInputStream ();

}if(isUpData){return super.getInputStream ();

}else{final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ());return newServletInputStream() {

@Overridepublic int read() throwsIOException {returnbais.read();

}

};

}

}publicString inputHandlers(ServletInputStream servletInputStream){

StringBuilder sb= newStringBuilder();

BufferedReader reader= null;try{

reader= new BufferedReader(new InputStreamReader(servletInputStream, Charset.forName("UTF-8")));

String line= "";while ((line = reader.readLine()) != null) {

sb.append(line);

}

}catch(IOException e) {

e.printStackTrace();

}finally{if (servletInputStream != null) {try{

servletInputStream.close();

}catch(IOException e) {

e.printStackTrace();

}

}if (reader != null) {try{

reader.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}

String requestUrl= StringUtils.replaceOnce(this.getRequestURI(), this.getContextPath(), StringUtils.EMPTY);boolean needFilter = false;

String key= "";

String param= "";for(Map.Entryentry : doNotFilterURLAndParamMap.entrySet()){

key=entry.getKey();int index = StringUtils.indexOf(key, "*");if (index > 0) {

String[] array= key.split("\\*");

StringBuffer stringBuffer= newStringBuffer();for(String s : array) {

stringBuffer.append(s).append("(.*)");

}

Pattern p=Pattern.compile(stringBuffer.toString());

Matcher m=p.matcher(requestUrl);if(m.find()) {

needFilter= true;

param=entry.getValue();break;

}

}else{if(requestUrl.equals(key)) {

needFilter= true;

param=entry.getValue();break;

}

}

}if(needFilter) { //有需要特殊处理的字段,不希望过滤标签

try{/*String param = doNotFilterURLAndParamMap.get(requestUrl);*/JSONObject jsonObject=JSONObject.parseObject(sb.toString());if(jsonObject.containsKey(param)) {

Object notFilterValue=jsonObject.get(param);

String cleanXSSParams=cleanXSS(sb.toString ());

JSONObject filteredJson=JSONObject.parseObject(cleanXSSParams);

filteredJson.put(param, notFilterValue);returnfilteredJson.toJSONString();

}else{returncleanXSS(sb.toString ());

}

}catch(Exception e) {

LOGGER.error("XssHttpServletRequestWrapper转换json数据失败",e);return cleanXSS(sb.toString ()); //异常时,就直接过滤,不管需要特殊处理的参数

}

}else{returncleanXSS(sb.toString ());

}

}/*** 过滤规则,这里不直接使用StringEscapeUtils.escapeHtml,因为获取的是一个json字符串,会将" 替换导致数据异常,没有""进行分割,无法正常注入到@RequestBody

*@paramvalue

*@return

*/

private staticString cleanXSS(String value) {

value= value.replaceAll("", ">");

value= value.replaceAll("%3C", "<").replaceAll("%3E", ">");//value = value.replaceAll("\\(", "(").replaceAll("\\)", ")");

value = value.replaceAll("%28", "(").replaceAll("%29", ")");//value = value.replaceAll("'", "'");

/*value = value.replaceAll("eval\\((.*)\\)", "");

value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");

value = value.replaceAll("script", "");*/

returnvalue;

}

}

感谢你的阅读,接外包、也找兼职

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值