欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot只需要几行代码,就可以防XSS攻击

程序员文章站 2022-03-10 17:42:44
前言可能很多同学在学习过程中自己做项目,很容易忽略XSS攻击。网上不少博客的自定义全局拦截器来实现XSS过滤,其实不需要这么麻烦,SpringBoot留有不少钩子(扩展点),据此我们可以巧妙地实现全局的XSS过滤。防止XSS攻击,一般有两种做法:1、转义Spring有提供工具类HtmlUtils来实现转义。个人比较喜欢这种方式,所以下面代码均采用转义处理。2、过滤敏感标签(将敏感标签去除)jsoup实现了非常强大的clean敏感标签的功能,但是我对jsoup了解并不多。接下来的...

前言

可能很多同学在学习过程中自己做项目,很容易忽略XSS攻击。网上不少博客的自定义全局拦截器来实现XSS过滤,其实不需要这么麻烦,SpringBoot留有不少钩子(扩展点),据此我们可以巧妙地实现全局的XSS过滤。

防止XSS攻击,一般有两种做法:

1、转义

Spring有提供工具类HtmlUtils来实现转义。个人比较喜欢这种方式,所以下面代码均采用转义处理。

2、过滤敏感标签(将敏感标签去除)

jsoup实现了非常强大的clean敏感标签的功能,但是我对jsoup了解并不多。

接下来的问题,就是:不适用拦截器,在哪切入,对参数进行转义处理呢?答案是:SpringMVC 进行参数绑定时!关于源码级别的理解和说明,我就不说了,因为能力有限。详情可参考:https://www.cnblogs.com/yourbatman/p/11218694.html

下面我会提供3种配置方式!个人比较推荐 方式3,因为WebMvcConfigurer本身就是为开发者定制的配置MVC的非常强大的扩展接口。

方式1

import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.util.HtmlUtils;

import java.beans.PropertyEditorSupport;

/**
 * String->String的类型转换器
 *
 * @author passerbyYSQ
 * @create 2021-02-22 17:26
 */
@Component
public class EscapeStringEditor extends PropertyEditorSupport {
    
    @Override
    public String getAsText() {
        Object value = getValue();
        return value != null ? value.toString() : "";
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        String escapedText = null;
        if (!StringUtils.isEmpty(text)) {
            escapedText = HtmlUtils.htmlEscape(text, "UTF-8");
        }
        setValue(escapedText);
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;

/**
 * @author passerbyYSQ
 * @create 2021-02-22 17:20
 */
@Component
public class MyWebBindingInitializer extends ConfigurableWebBindingInitializer {

    @Autowired
    private EscapeStringEditor escapeStringEditor;

    @Override
    public void initBinder(WebDataBinder binder) {
        super.initBinder(binder); // 不能少!!!
        // 注册自定义的类型转换器
        binder.registerCustomEditor(String.class, escapeStringEditor);
    }

}

方式2

public class BaseController {

    @Autowired
    private EscapeStringEditor escapeStringEditor;

    @InitBinder
    public void initBinder(ServletRequestDataBinder binder) {
        binder.registerCustomEditor(String.class, escapeStringEditor);
    }

需要XSS防护的Controller的需要继承该BaseController

方式3

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.util.HtmlUtils;

/**
 * @author passerbyYSQ
 * @create 2021-02-22 23:15
 */
@Component
public class EscapeStringConverter implements Converter<String, String> {

    @Override
    public String convert(String s) {
        return StringUtils.isEmpty(s) ? s : HtmlUtils.htmlEscape(s);
    }

}
package net.ysq.webchat.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author passerbyYSQ
 * @create 2021-01-29 14:41
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Autowired
    private EscapeStringConverter escapeStringConverter;

    /**
     * 在参数绑定时,自定义String->String的转换器,
     * 在转换逻辑中对参数值进行转义,从而达到防XSS的效果
     *
     * @param registry
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(escapeStringConverter);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                // 路径不包括contextPath部分
                .excludePathPatterns("/user/login", "/user/logout", "/index/test1");
    }

    /**
     * 前后端分离需要解决跨域问题
     *
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH")
                .allowCredentials(true).maxAge(3600);
    }

}

 

本文地址:https://blog.csdn.net/qq_43290318/article/details/113963435