• 首页
  • 邻居
  • 关于
  • 归档
  • 搜索
  • 夜间模式
    ©2020-2026  我的学习笔记 Theme by OneBlog

    我的学习笔记博客

    搜索
    标签
    # 随笔 # Java # 教程 # openwrt # Mysql # SQL # 爬虫 # post # Js调优 # MAVEN
  • 首页>
  • 随笔>
  • 正文
  • springboot 实现xss过滤

    2023年09月15日 957 阅读 0 评论 6986 字
    package com.jinw.cms.aspectj;
    
    import com.jinw.cms.aspectj.annotation.XssIgnore;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.AsyncHandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Objects;
    
    public class XssInterceptor implements AsyncHandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            if (handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                XssIgnore xssIgnore = handlerMethod.getMethodAnnotation(XssIgnore.class);
                if (Objects.nonNull(xssIgnore)) {
                    XssContextHolder.ignore();
                }
            }
            return true;
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            XssContextHolder.remove();
        }
    
        /**
         * 如果返回一个current类型的变量,会启用一个新的线程。执行完preHandle方法之后立即会调用afterConcurrentHandlingStarted
         * 然后新线程再以次执行preHandle,postHandle,afterCompletion**
         */
        @Override
        public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            XssContextHolder.remove();
        }
    }
    
    package com.jinw.cms.aspectj;
    
    import com.fasterxml.jackson.core.JacksonException;
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonToken;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    import com.fasterxml.jackson.databind.JsonMappingException;
    import com.fasterxml.jackson.databind.type.LogicalType;
    import com.jinw.cms.entity.XssMode;
    import com.jinw.utils.cms.HtmlUtils;
    import com.jinw.utils.cms.StringUtils;
    import lombok.RequiredArgsConstructor;
    
    import java.io.IOException;
    import java.util.Objects;
    
    @RequiredArgsConstructor
    public class XssDeserializer extends JsonDeserializer<String> {
    
        private final XssMode mode;
    
        @Override
        public LogicalType logicalType() {
            return LogicalType.Textual;
        }
    
        @Override
        public String getNullValue(DeserializationContext ctxt) throws JsonMappingException {
            return StringUtils.EMPTY;
        }
    
        @Override
        public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
            if (p.hasToken(JsonToken.VALUE_STRING)) {
                return deal(p.getText());
            }
            JsonToken token = p.getCurrentToken();
            if (token.isScalarValue()) {
                String text = p.getValueAsString();
                if (text != null) {
                    return text;
                }
            }
            return (String) ctxt.handleUnexpectedToken(String.class, p);
        }
    
        private String deal(String text) {
            if (Objects.nonNull(text) && !XssContextHolder.isIgnore()) {
                if (mode == XssMode.CLEAN) {
                    text = HtmlUtils.clean(text);
                } else {
                    text = HtmlUtils.escape(text);
                }
            }
            return text;
        }
    }
    package com.jinw.cms.aspectj;
    
    import java.util.Objects;
    
    public class XssContextHolder {
    
        private static final ThreadLocal<Boolean> CONTEXT = new ThreadLocal<>();
    
        /**
         * 默认为true
         */
        public static boolean isIgnore() {
            return Objects.isNull(CONTEXT.get()) ? true : CONTEXT.get();
        }
    
        public static void ignore() {
            CONTEXT.set(true);
        }
    
        public static void remove() {
            CONTEXT.remove();
        }
    }
    
    package com.jinw.cms.config.properties;
    
    import com.jinw.cms.entity.XssMode;
    import lombok.Getter;
    import lombok.Setter;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    import java.util.List;
    
    @Setter
    @Getter
    @ConfigurationProperties(prefix = "xss")
    public class XssProperties {
    
        /**
         * 是否开启XSS过滤
         */
        private boolean enabled;
    
        /**
         * 处理方式
         */
        private XssMode mode;
    
        /**
         * 不进行处理的路径
         */
        private List<String> excludes;
    
        /**
         * 处理指定路径
         */
        private List<String> urlPatterns;
    }
    
    package com.jinw.cms.config;
    
    import com.google.common.collect.Lists;
    import com.jinw.cms.aspectj.XssDeserializer;
    import com.jinw.cms.aspectj.XssInterceptor;
    import com.jinw.cms.config.properties.XssProperties;
    import com.jinw.utils.cms.StringUtils;
    import lombok.RequiredArgsConstructor;
    import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    import java.util.Collections;
    import java.util.List;
    
    @RequiredArgsConstructor
    @Configuration
    @EnableConfigurationProperties(XssProperties.class)
    public class XssConfig implements WebMvcConfigurer {
    
        private final XssProperties xssProperties;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            if (xssProperties.isEnabled()) {
                List<String> urlPatterns = xssProperties.getUrlPatterns();
                if (StringUtils.isEmpty(urlPatterns)) {
                    urlPatterns = Lists.newArrayList();
                    urlPatterns.add("/**");
                }
                List<String> excludes = xssProperties.getExcludes();
                if (StringUtils.isEmpty(excludes)) {
                    excludes = Collections.emptyList();
                }
                //addPathPatterns(urlPatterns) 对所有请求都拦截,但是排除了 excludePathPatterns(excludes) 请求的拦截。
                registry.addInterceptor(new XssInterceptor()).
                        addPathPatterns(urlPatterns)
                        .excludePathPatterns(excludes).order(Ordered.LOWEST_PRECEDENCE);
            }
        }
    
        @Bean
        public Jackson2ObjectMapperBuilderCustomizer xssCustomizer() {
            return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.deserializerByType(String.class,
                    new XssDeserializer(xssProperties.getMode()));
        }
    }
    package com.jinw.cms.aspectj.annotation;
    
    import java.lang.annotation.*;
    
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface XssIgnore {
    
    }
    
    # 防止XSS攻击
    xss:
      # 过滤开关
      enabled: true
      mode: clean
    
    本文著作权归作者 [ admin ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。
    取消回复

    发表留言
    回复

    首页邻居关于归档
    Copyright©2020-2026  All Rights Reserved.  Load:0.017 s
    京ICP备18019712号
    Theme by OneBlog V3.6.5
    夜间模式

    开源不易,请尊重作者版权,保留基本的版权信息。