Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数

Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数

欢迎大家去我的个人网站踩踩 点这里哦

一、前言

最近项目做安全测试,发现存在XSS攻击的可能,于是乎上网找找看,找了很多基本都是继承HttpServletRequestWrapper,对getParam、getQueryString等获取参数的方法进行重写,对参数进行html转义,马上找一个加上试了试,可是发现保存的对象还是没有转义的,后来才想到项目是前后端分离,基本都是@RequestBody注解接收application/json格式参数,通过以上方法是获取不到参数的。

二、网上大多数的解决方案

XssHttpServletRequestWrapper、XssFilter

package com.sino.teamwork.common.extension;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.text.StringEscapeUtils;


public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getQueryString() {
        return StringEscapeUtils.escapeHtml4(super.getQueryString());
    }

    @Override
    public String getParameter(String name) {
        return StringEscapeUtils.escapeHtml4(super.getParameter(name));
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if (ArrayUtils.isEmpty(values)) {
            return values;
        }
        int length = values.length;
        String[] escapeValues = new String[length];
        for (int i = 0; i < length; i++) {
            escapeValues[i] = StringEscapeUtils.escapeHtml4(values[i]);
        }
        return escapeValues;
    }

}
package com.sino.teamwork.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Component;

import com.sino.teamwork.common.extension.XssHttpServletRequestWrapper;

/**
 * 
 * @ClassName: XssFilter
 * @Description:TODO(防止xss的过滤器)<br>
 * RequsestBody参数通过修改MappingJackson2HttpMessageConverter来过滤
 * @author: guomh
 * @date: 2020年4月07日 下午5:05:51
 * 
 * @Copyright: 2020
 *
 */
@WebFilter(filterName = "xssFilter", urlPatterns = "/*", asyncSupported = true)
@Component
public class XssFilter implements Filter {

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub
        HttpServletRequest req = (HttpServletRequest) request;
        XssHttpServletRequestWrapper xssRequestWrapper = new XssHttpServletRequestWrapper(req);
        chain.doFilter(xssRequestWrapper, response);
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
    }

 
}

这个只能解决下表的前两种Content-Type方式传的参数

Content-Type 传参方式 接收方式
application/x-www-form-urlencoded 表单key-value HttpServletRequest Parameters 获取
multipart/form-data 表单key-value HttpServletRequest Parameters 获取
application/json json格式文本 HttpServletRequest IO流获取

三、RequestBody注解接收json格式参数解决方法

用@RequestBody 注解会使用默认转换器来进行转换,默认转换器初始化过程是这样的,springboot默认会用 MappingJackson2XmlHttpMessageConverter来转换json

看下官网的文档描述

An HttpMessageConverter implementation that can read and write JSON using Jackson’s ObjectMapper. JSON mapping can be customized as needed through the use of Jackson’s provided annotations. When further control is needed, a custom ObjectMapper can be injected through the ObjectMapper property for cases where custom JSON serializers/deserializers need to be provided for specific types. By default this converter supports ( application/json).

现在目标很明确了,就是要把默认的 MappingJackson2XmlHttpMessageConverter 给替换掉,我们自己写,然后在转换json参数后再进行html转义,理所当然的想到如下办法

@Bean
HttpMessageConverter<?> MappingJackson2HttpMessageConverter() {

}

我们看一下SpringMVC配置 WebMvcConfigurationSupport 里面获取 MessageConverter 的方法,如下图

Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数

里面有几个重要的方法,我们看下这几个方法的注释:

addDefaultHttpMessageConverters是系统默认的Converters,我们此方法最重要的一部分,MappingJackson2HttpMessageConverter是new出来的对象,所以并没有被spring容器管理,所以这也就说明了我们通过上面@Bean注解是无法替换掉系统默认的

Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数

configureMessageConverters 是自定义的MessageConverters,重写此方法,就是自己手动配置,不会采用springboot默认配置

Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数

extendMessageConverters的注释,我们看是扩展或修改converters的,因此我们也通过此方法也可以修改系统默认的

Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数

因此我们看到通过重写 configureMessageConverters 、extendMessageConverters 两个方法都可以修改系统默认的转换器

方法一:

重写 configureMessageConverters,我们需要把addDefaultHttpMessageConverters里面系统默认的转换器都写一遍,以保证其他的转化器有效,我们可以把 addDefaultHttpMessageConverters 源码复制出来,在 new MappingJackson2HttpMessageConverter 那里,我们可以 new 一个自定义的MappingJackson2HttpMessageConverter,但是我不建议用此方法,因为addDefaultHttpMessageConverters里面的内容很多,还有一些私有变量,复制出来有些不方便,还容易出错。

方法二:

重写extendMessageConverters,此方法注释说就是让来修改已经配置好的转化器列表呢,我们只需要遍历列表,找到MappingJackson2HttpMessageConverter,我们可以根据类型来判断哪个是 MappingJackson2HttpMessageConverter ,然后移除(注意遍历移除一定要用迭代器),把自定义的添加进去就好了,我们写在 WebMvcConfig 里


@Configuration
public class WebMvcConfig  extends WebMvcConfigurationSupport {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
        /**
         * 替换默认的MappingJackson2HttpMessageConverter,过滤(json请求参数)xss
         */
    	ListIterator<HttpMessageConverter<?>> listIterator = messageConverters.listIterator();
    	while(listIterator.hasNext()) {
    		HttpMessageConverter<?> next = listIterator.next();
    		if(next instanceof MappingJackson2HttpMessageConverter) {
    			listIterator.remove();
    			break;
    		}
    	}
        messageConverters.add(getMappingJackson2HttpMessageConverter());

    }
    
    public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
        // 创建自定义ObjectMapper
        SimpleModule module = new SimpleModule();
        module.addDeserializer(String.class, new JsonHtmlXssDeserializer(String.class));
        ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.getApplicationContext()).build();
        objectMapper.registerModule(module);
        // 创建自定义消息转换器
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        //设置中文编码格式
        List<MediaType> list = new ArrayList<>();
        list.add(MediaType.APPLICATION_JSON_UTF8);
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(list);
        return mappingJackson2HttpMessageConverter;
    }

}

/**
 * 对入参的json进行转义
 */
class JsonHtmlXssDeserializer extends JsonDeserializer<String> {

    public JsonHtmlXssDeserializer(Class<String> string) {
        super();
    }

    @Override
    public Class<String> handledType() {
        return String.class;
    }

    @Override
    public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        String value = jsonParser.getValueAsString();
        if (value != null) {
            return StringEscapeUtils.escapeHtml4(value.toString());
        }
        return value;
    }
}

我们看到最重要的代码其实是ObjectMapper 里面的 JsonHtmlXssDeserializer,这个解析器是解析json字符串时调用的,我们在里面对解析出来的参数进行转义就可以了。

方法三(不行):

网上还有一个方法是替换默认的ObjectMapper的,从第二种方法我们可以看出来,其实最终是为了替换默认的ObjectMapper,于是乎网上有了这种写法

 /**
 * 过滤json类型的
 * @param builder
 * @return
 */
 @Bean
 @Primary
 public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
 //解析器
 ObjectMapper objectMapper = builder.createXmlMapper(false).build();
 //注册xss解析器
 SimpleModule xssModule = new SimpleModule("XssStringJsonSerializer");
 xssModule.addSerializer(new XssStringJsonSerializer());
 objectMapper.registerModule(xssModule);
 //返回
 return objectMapper;
 }

也是想用 @bean 注解来替换默认的ObjectMapper,这样真的可以吗,这样其实跟用@Bean注解替换 MappingJackson2XmlHttpMessageConverter 是一样的,我们看下源码

Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数

默认是用Jackson2ObjectMapperBuilder来构造ObjectMapper的,我们进去build方法看一下,可以看到也是new出来的,并没有被spring容器管理,所以这种方法不可以

Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数

四、总结

还是那句话,网上很多的文章代码估计不知道测过没有,拿来用很多都不适用,我们可以拿来参考,找到其中的思路,再自己分析原理,理解透了这样子才能真正解决自己的问题。最后欢迎大家到我的个人网站看看,点这里

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/111314.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java outputstream转为inputstream(java传递流)

    本文转自 https://blog.csdn.net/lmy86263/article/details/60479350在Java中InputStream和String之间的转化十分普遍,本文主要是总结一下转换的各种方法,包括JDK原生提供的,还有一些外部依赖提供的。1、InputStream转化为String1.1JDK原生提供方法一:byte[]bytes=newbyt…

    2022年4月16日
    76
  • 游戏场景建模用什么软件?

    游戏场景建模用什么软件?游戏场景建模用什么软件?想要入行游戏领域第一步大家要知道建模要用到的软件“ZBrush”“3DMax”“MAYA”ZBrush:高模的制作软件,用ZB做角色是很很好的,可是难度系数也挺大,平常要多看看人体的构造,或找人体写真来把控不一样的人体肌肉转变,多了解多实践。3DMax:3DMax相对而言是一个较为简单易学的软件,用于做建筑场景也很的好使。可是3D要想把他学精依然要1个步骤的,因此掌握软件很重要,3D建模的软件物品很杂很碎,还需多练才最重要,多做一些实例熟记的也差不多了。MAYA:熟记人

    2022年5月19日
    44
  • SQLite下载、安装和使用并Qt链接SQLIte全部教程(windows)

    SQLite下载、安装和使用并Qt链接SQLIte全部教程(windows)第一步 下载 SQLIte 下载地址 https www sqlite org download html 下载两个内容 sqlite dll win64 x64 3360000 zipsqlite tools win32 x86 3360000 zip 下载完后直接解压 放到到一个文件夹下 这个文件夹可以随便在哪里 如下图 第二步 使用 SQLite 网上好多教程都是到这一步就配置环境变量 不知道他们脑子咋想的 轻量级数据库 SQLIte 本来就应该随着项目到处走 直接在解压且合并后

    2025年7月21日
    2
  • redis分布式锁的应用场景_分布式锁redis实现方式

    redis分布式锁的应用场景_分布式锁redis实现方式RedLock分布式锁 基于Redis实现分布式锁的方式名叫Redlock 安全特性:互斥访问,即永远只有一个client能拿到锁 避免死锁:最终client都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的clientcrash了或者出现了网络分区(两个完全不连通的区域,美国的网咱们登不上去) 容错性:只要大部分Redis节点存活就可以正常提供服务 Redis集群及应用场景热点数据存取数据优先从Redis操作,如果不存在再从文

    2025年10月7日
    3
  • android之 Activity跳转出现闪屏

    android之 Activity跳转出现闪屏属于个人开发小知识应用Activity之间相互跳转时可能会出现闪屏现象原因:由于finish原因,网传,在onPause()里延迟3s使用finish。解决方案:方案一://我的解决方案,自定义style然后找到对应的Activity进行设置<stylename=”Theme”parent=”android:Theme”><itemname=…

    2022年5月11日
    36
  • Excel之VBA简单宏编程

    Excel之VBA简单宏编程Excel之VBA简单宏编程excel是一款很经典的数据分析的工具,里面包含了很多内置函数,但实际情况有时却复杂得多,而excel的宏编程提供了自定义函数的功能,正好有老师需要帮忙做一些数据分析,就学习了一下,下面是我的学习笔记。本人使用的是excel2013。有出入的地方可以参考。Excel之VBA简单宏编程1、准备工作2、VBA编程2.1模块声明2.2变量声明及赋值2…

    2022年6月13日
    87

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号