赞
踩
这几天自己学习了一下SpringBoot项目怎么预防Xss攻击,这里记录一下怎么防止Xss攻击的代码,等以后有需要用到的话,自己可以快速找到。
这里需要注意的是1.5到1.9版本有高危漏洞,需要升级到1.10.0以上版本,这是当前时间最新的版本。
<!--commons-text工具包,用于xss攻击对特殊参数字符做转换,1.5到1.9版本有高危漏洞-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
处理非application/json提交方式使用下面二个类:
XssFilter类,重写doFilter方法,然后调用XssHttpServletRequestWrapper类。
XssHttpServletRequestWrapper类,只能对提交方式为x-www-form-urlencoded和form-data做特殊字符转换,不能对提交方式为application/json的数据格式做转换,如果没有指定提交方式,浏览器默认提交方式为x-www-form-urlencoded。
处理application/json提交方式使用下面三个类:
XssStringJsonDeSerializer类,这个类主要是对前端传递的数据格式为json格式的参数进行特殊字符转义。
XssStringJsonSerializer类,这个类主要是处理后端向前端返回的json数据,将数据里面包含的特殊字符进行转义后发送。
JacksonConfig类,调用上面2个自定义的序列化类,没有这个配置类,上面的2个类不会生效。
测试代码:
在谷歌浏览器直接输入接口请求测试如下:
看到它这里是直接弹窗打印了,想要的返回值应该是浏览器页面中返回的是值才对。
package com.hjl.mall.filter; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /** * XSS过滤器 */ @Component public class XssFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } //重写doFilter方法 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { /** * 1. 重写getParamter方法 * 2. 在getParamter中判断属性,然后对特殊字符进行编码,使用官方提供的工具类. * 3. 继续提交请求 */ chain.doFilter(new XssHttpServletRequestWrapper( (HttpServletRequest) request), response); } @Override public void destroy() { } }
package com.hjl.mall.filter; import org.apache.commons.text.StringEscapeUtils; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.IOException; import java.util.Objects; /** * @ClassName XssHttpServletRequestWrapper * @Description 重写wrapper,只能对提交方式为x-www-form-urlencoded和form-data做特殊字符转换,不能对提交方式为json的数据格式做转换 * @Version 1.0 */ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); } @Override public String getHeader(String name) { return StringEscapeUtils.escapeHtml4(super.getHeader(name)); } @Override public String getQueryString() { return StringEscapeUtils.escapeHtml4(super.getQueryString()); } @Override public String getParameter(String name) { return StringEscapeUtils.escapeHtml4(super.getParameter(name)); } @Override public ServletInputStream getInputStream() throws IOException { return super.getInputStream(); } @Override public String[] getParameterValues(String name) { String[] parameterValues = super.getParameterValues(name); if (Objects.isNull(parameterValues)) { return null; } //对请求参数里面的特殊字符进行转义 for (int i = 0; i < parameterValues.length; i++) { parameterValues[i] = StringEscapeUtils.escapeHtml4(parameterValues[i]); } return parameterValues; } }
可以看到达到了自己想要的结果,没有弹窗显示了,直接将结果正确显示到了页面中。
转义后的值如下:
但是这样对于json格式的数据起不到作用,如下图,发现并没有对里面的<、>、"这三个特殊符号进行转义:
package com.hjl.mall.filter; import java.io.IOException; import org.apache.commons.text.StringEscapeUtils; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; /** * 对前端传递的数据格式为json格式的参数进行特殊字符转义 */ public class XssStringJsonDeSerializer extends JsonDeserializer<String> { @Override public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { //对json格式的参数值进行转义 return StringEscapeUtils.escapeHtml4(jsonParser.getText()); } }
package com.hjl.mall.filter; import java.io.IOException; import java.util.Objects; import org.apache.commons.text.StringEscapeUtils; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; /** * 处理后端向前端返回的json数据,将数据进行转义后发送 */ public class XssStringJsonSerializer extends JsonSerializer<String> { @Override public Class<String> handledType() { return String.class; } @Override public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (Objects.nonNull(value)) { //将json格式数据转义后发送给前端 String encodedValue = StringEscapeUtils.escapeHtml4(value); jsonGenerator.writeString(encodedValue); } } }
package com.hjl.mall.config; import com.hjl.mall.filter.XssStringJsonDeSerializer; import com.hjl.mall.filter.XssStringJsonSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; /** * 对json格式数据做序列化和反序列化操作,防止xss攻击 * XssFilter类 * XssHttpServletRequestWrapper类 * XssStringJsonDeSerializer类 * XssStringJsonSerializer类 * JacksonConfig类 * 这5个类是一起的,都是用来防止xss攻击,前2个类是用来处理提交方式为x-www-form-urlencoded和form-data做特殊字符转换 * 后面三类是对application/json提交方式做处理 */ @Configuration public class JacksonConfig implements WebMvcConfigurer{ @Bean public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); //注入自定义的序列化工具,将@RequestBody的json格式参数做转义处理 SimpleModule simpleModule = new SimpleModule(XssStringJsonSerializer.class.getSimpleName()); //只对入参json进行特殊字符转义 simpleModule.addDeserializer(String.class, new XssStringJsonDeSerializer()); //对返回给前端的json数据(特殊字符)进行转义,这里暂时注释掉,当前项目暂不需要对返回给前端的数据进行转义 //simpleModule.addSerializer(String.class, new XssStringJsonSerializer()); objectMapper.registerModule(simpleModule); return objectMapper; } }
测试代码:
因为是post请求,所以这里使用postman工具对接口进行测试:
发现已经转义成功。
这个JacksonConfig类 里面的代码,我注释掉了对返回json数据格式做转义的处理。
不注释掉的话,会进行2次转义处理,效果如下:
它这里先是对入参<转义为<
,然后又将<
里面的&符合在返回给前端的时候又进行了一次转义,所以变成了&lt;
。
这一种会出现这一种情况,我这里用txt简单写一个html页面代码:
然后我将txt后缀改为html,效果如下:
所以这里JacksonConfig类里面的XssStringJsonSerializer类调用需要根据自己的项目实际情况需要是否引用。
好了,笔记先做到这里,等以后自己有需要直接引用即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。