mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-30 23:00:11 +08:00 
			
		
		
		
	refactor(web): 优化 XSS 过滤部分代码
This commit is contained in:
		| @@ -37,7 +37,7 @@ public class PropertiesConstants { | |||||||
|     /** |     /** | ||||||
|      * 线程池配置 |      * 线程池配置 | ||||||
|      */ |      */ | ||||||
|     public static final String THREAD_POOL = CONTINEW_STARTER + ".thread-pool"; |     public static final String THREAD_POOL = CONTINEW_STARTER + StringConstants.DOT + "thread-pool"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Spring Doc 配置 |      * Spring Doc 配置 | ||||||
| @@ -47,7 +47,7 @@ public class PropertiesConstants { | |||||||
|     /** |     /** | ||||||
|      * Spring Doc Swagger UI 配置 |      * Spring Doc Swagger UI 配置 | ||||||
|      */ |      */ | ||||||
|     public static final String SPRINGDOC_SWAGGER_UI = SPRINGDOC + ".swagger-ui"; |     public static final String SPRINGDOC_SWAGGER_UI = SPRINGDOC + StringConstants.DOT + "swagger-ui"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 安全配置 |      * 安全配置 | ||||||
| @@ -67,52 +67,52 @@ public class PropertiesConstants { | |||||||
|     /** |     /** | ||||||
|      * Web 配置 |      * Web 配置 | ||||||
|      */ |      */ | ||||||
|     public static final String WEB = CONTINEW_STARTER + ".web"; |     public static final String WEB = CONTINEW_STARTER + StringConstants.DOT + "web"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 跨域配置 |      * 跨域配置 | ||||||
|      */ |      */ | ||||||
|     public static final String CORS = WEB + ".cors"; |     public static final String CORS = WEB + StringConstants.DOT + "cors"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 链路配置 |      * 链路配置 | ||||||
|      */ |      */ | ||||||
|     public static final String TRACE = WEB + ".trace"; |     public static final String TRACE = WEB + StringConstants.DOT + "trace"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 链路配置 |      * XSS 配置 | ||||||
|      */ |      */ | ||||||
|     public static final String XSS = WEB + ".xss"; |     public static final String XSS = WEB + StringConstants.DOT + "xss"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 日志配置 |      * 日志配置 | ||||||
|      */ |      */ | ||||||
|     public static final String LOG = CONTINEW_STARTER + ".log"; |     public static final String LOG = CONTINEW_STARTER + StringConstants.DOT + "log"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 存储配置 |      * 存储配置 | ||||||
|      */ |      */ | ||||||
|     public static final String STORAGE = CONTINEW_STARTER + ".storage"; |     public static final String STORAGE = CONTINEW_STARTER + StringConstants.DOT + "storage"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 本地存储配置 |      * 本地存储配置 | ||||||
|      */ |      */ | ||||||
|     public static final String STORAGE_LOCAL = STORAGE + ".local"; |     public static final String STORAGE_LOCAL = STORAGE + StringConstants.DOT + "local"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 验证码配置 |      * 验证码配置 | ||||||
|      */ |      */ | ||||||
|     public static final String CAPTCHA = CONTINEW_STARTER + ".captcha"; |     public static final String CAPTCHA = CONTINEW_STARTER + StringConstants.DOT + "captcha"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 图形验证码配置 |      * 图形验证码配置 | ||||||
|      */ |      */ | ||||||
|     public static final String CAPTCHA_GRAPHIC = CAPTCHA + ".graphic"; |     public static final String CAPTCHA_GRAPHIC = CAPTCHA + StringConstants.DOT + "graphic"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 行为验证码配置 |      * 行为验证码配置 | ||||||
|      */ |      */ | ||||||
|     public static final String CAPTCHA_BEHAVIOR = CAPTCHA + ".behavior"; |     public static final String CAPTCHA_BEHAVIOR = CAPTCHA + StringConstants.DOT + "behavior"; | ||||||
|  |  | ||||||
|     private PropertiesConstants() { |     private PropertiesConstants() { | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -25,13 +25,13 @@ import org.slf4j.LoggerFactory; | |||||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||||||
|  | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; | ||||||
| import org.springframework.boot.context.properties.EnableConfigurationProperties; | import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||||
| import org.springframework.boot.web.servlet.FilterRegistrationBean; | import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.context.annotation.Primary; | import org.springframework.context.annotation.Primary; | ||||||
| import org.springframework.core.Ordered; | import org.springframework.core.Ordered; | ||||||
| import top.charles7c.continew.starter.core.constant.PropertiesConstants; | import top.charles7c.continew.starter.core.constant.PropertiesConstants; | ||||||
| import top.charles7c.continew.starter.core.constant.StringConstants; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 链路跟踪自动配置 |  * 链路跟踪自动配置 | ||||||
| @@ -41,6 +41,7 @@ import top.charles7c.continew.starter.core.constant.StringConstants; | |||||||
|  * @since 1.3.0 |  * @since 1.3.0 | ||||||
|  */ |  */ | ||||||
| @AutoConfiguration | @AutoConfiguration | ||||||
|  | @ConditionalOnWebApplication | ||||||
| @EnableConfigurationProperties(TraceProperties.class) | @EnableConfigurationProperties(TraceProperties.class) | ||||||
| @ConditionalOnProperty(prefix = PropertiesConstants.TRACE, name = PropertiesConstants.ENABLED, havingValue = "true") | @ConditionalOnProperty(prefix = PropertiesConstants.TRACE, name = PropertiesConstants.ENABLED, havingValue = "true") | ||||||
| public class TraceAutoConfiguration { | public class TraceAutoConfiguration { | ||||||
| @@ -70,10 +71,9 @@ public class TraceAutoConfiguration { | |||||||
|      * TLog 过滤器配置 |      * TLog 过滤器配置 | ||||||
|      */ |      */ | ||||||
|     @Bean |     @Bean | ||||||
|     public FilterRegistrationBean<TLogServletFilter> filterRegistration() { |     public FilterRegistrationBean<TLogServletFilter> tLogServletFilter() { | ||||||
|         FilterRegistrationBean<TLogServletFilter> registration = new FilterRegistrationBean<>(); |         FilterRegistrationBean<TLogServletFilter> registration = new FilterRegistrationBean<>(); | ||||||
|         registration.setFilter(new TLogServletFilter(traceProperties)); |         registration.setFilter(new TLogServletFilter(traceProperties)); | ||||||
|         registration.addUrlPatterns(StringConstants.PATH_PATTERN_CURRENT_DIR); |  | ||||||
|         registration.setOrder(Ordered.HIGHEST_PRECEDENCE); |         registration.setOrder(Ordered.HIGHEST_PRECEDENCE); | ||||||
|         return registration; |         return registration; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -25,18 +25,22 @@ import org.springframework.context.annotation.Bean; | |||||||
| import top.charles7c.continew.starter.core.constant.PropertiesConstants; | import top.charles7c.continew.starter.core.constant.PropertiesConstants; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * XSS配置 |  * XSS 过滤自动配置 | ||||||
|  * |  * | ||||||
|  * @author whhya |  * @author whhya | ||||||
|  * @since 1.0.0 |  * @since 2.0.0 | ||||||
|  */ |  */ | ||||||
| @AutoConfiguration | @AutoConfiguration | ||||||
| @ConditionalOnWebApplication | @ConditionalOnWebApplication | ||||||
| @ConditionalOnProperty(prefix = PropertiesConstants.XSS, name = PropertiesConstants.ENABLED, havingValue = "true") |  | ||||||
| @EnableConfigurationProperties(XssProperties.class) | @EnableConfigurationProperties(XssProperties.class) | ||||||
|  | @ConditionalOnProperty(prefix = PropertiesConstants.XSS, name = PropertiesConstants.ENABLED, havingValue = "true") | ||||||
| public class XssAutoConfiguration { | public class XssAutoConfiguration { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * XSS 过滤器配置 | ||||||
|  |      */ | ||||||
|     @Bean |     @Bean | ||||||
|     public FilterRegistrationBean<XssFilter> XssFilter(XssProperties xssProperties) { |     public FilterRegistrationBean<XssFilter> xssFilter(XssProperties xssProperties) { | ||||||
|         FilterRegistrationBean<XssFilter> registrationBean = new FilterRegistrationBean<>(); |         FilterRegistrationBean<XssFilter> registrationBean = new FilterRegistrationBean<>(); | ||||||
|         registrationBean.setFilter(new XssFilter(xssProperties)); |         registrationBean.setFilter(new XssFilter(xssProperties)); | ||||||
|         return registrationBean; |         return registrationBean; | ||||||
|   | |||||||
| @@ -29,10 +29,10 @@ import java.io.IOException; | |||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * xss过滤器 |  * XSS 过滤器 | ||||||
|  * |  * | ||||||
|  * @author whhya |  * @author whhya | ||||||
|  * @since 1.0.0 |  * @since 2.0.0 | ||||||
|  */ |  */ | ||||||
| public class XssFilter implements Filter { | public class XssFilter implements Filter { | ||||||
|  |  | ||||||
| @@ -53,58 +53,46 @@ public class XssFilter implements Filter { | |||||||
|     public void doFilter(ServletRequest servletRequest, |     public void doFilter(ServletRequest servletRequest, | ||||||
|                          ServletResponse servletResponse, |                          ServletResponse servletResponse, | ||||||
|                          FilterChain filterChain) throws IOException, ServletException { |                          FilterChain filterChain) throws IOException, ServletException { | ||||||
|         HttpServletRequest req = (HttpServletRequest) servletRequest; |         // 未开启 XSS 过滤,则直接跳过 | ||||||
|         //未开启xss过滤,则直接跳过 |         if (servletRequest instanceof HttpServletRequest request && xssProperties.isEnabled()) { | ||||||
|         if (!xssProperties.isEnabled()) { |             // 放行路由:忽略 XSS 过滤() | ||||||
|             filterChain.doFilter(req, servletResponse); |             List<String> excludePatterns = xssProperties.getExcludePatterns(); | ||||||
|  |             if (CollectionUtil.isNotEmpty(excludePatterns) && isMatchPath(request.getServletPath(), excludePatterns)) { | ||||||
|  |                 filterChain.doFilter(request, servletResponse); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |             // 拦截路由:执行 XSS 过滤 | ||||||
|         //限定url地址 |             List<String> includePatterns = xssProperties.getIncludePatterns(); | ||||||
|         List<String> pathPatterns = xssProperties.getPathPatterns(); |             if (CollectionUtil.isNotEmpty(includePatterns)) { | ||||||
|  |                 if (isMatchPath(request.getServletPath(), includePatterns)) { | ||||||
|         //判断是否匹配需要忽略地址 |                     filterChain.doFilter(new XssServletRequestWrapper(request), servletResponse); | ||||||
|         List<String> pathExcludePatterns = xssProperties.getPathExcludePatterns(); |  | ||||||
|         if (CollectionUtil.isNotEmpty(pathPatterns)) { |  | ||||||
|             if (isMatchPath(req.getServletPath(), pathExcludePatterns)) { |  | ||||||
|                 filterChain.doFilter(req, servletResponse); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         //如果存在则限定path拦截 |  | ||||||
|         if (CollectionUtil.isNotEmpty(pathPatterns)) { |  | ||||||
|             //未匹配上限定地址,则直接不过滤 |  | ||||||
|             if (isMatchPath(req.getServletPath(), pathPatterns)) { |  | ||||||
|                 filterChain.doFilter(new XssServletRequestWrapper(req), servletResponse); |  | ||||||
|                 return; |  | ||||||
|                 } else { |                 } else { | ||||||
|                 filterChain.doFilter(req, servletResponse); |                     filterChain.doFilter(request, servletResponse); | ||||||
|  |                 } | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |             // 默认:执行 XSS 过滤 | ||||||
|  |             filterChain.doFilter(new XssServletRequestWrapper(request), servletResponse); | ||||||
|  |             return; | ||||||
|         } |         } | ||||||
|  |         filterChain.doFilter(servletRequest, servletResponse); | ||||||
|         //默认拦截 |  | ||||||
|         filterChain.doFilter(new XssServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 判断数组中是否存在匹配的路径 |      * 判断数组中是否存在匹配的路径 | ||||||
|      * |      * | ||||||
|      * @param requestURL   请求地址 |      * @param requestUrl   请求地址 | ||||||
|      * @param pathPatterns 指定匹配路径 |      * @param pathPatterns 指定匹配路径 | ||||||
|      * @return true 匹配 false 不匹配 |      * @return true:匹配;false:不匹配 | ||||||
|      */ |      */ | ||||||
|     private static boolean isMatchPath(String requestURL, List<String> pathPatterns) { |     private static boolean isMatchPath(String requestUrl, List<String> pathPatterns) { | ||||||
|         for (String pattern : pathPatterns) { |         for (String pattern : pathPatterns) { | ||||||
|             PathPattern pathPattern = PathPatternParser.defaultInstance.parse(pattern); |             PathPattern pathPattern = PathPatternParser.defaultInstance.parse(pattern); | ||||||
|             PathContainer pathContainer = PathContainer.parsePath(requestURL); |             PathContainer pathContainer = PathContainer.parsePath(requestUrl); | ||||||
|             boolean matches = pathPattern.matches(pathContainer); |             if (pathPattern.matches(pathContainer)) { | ||||||
|             if (matches) { |  | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -23,27 +23,32 @@ import java.util.ArrayList; | |||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * xss配置属性 |  * XSS 过滤配置属性 | ||||||
|  * |  * | ||||||
|  * @author whhya |  * @author whhya | ||||||
|  * @since 1.0.0 |  * @since 2.0.0 | ||||||
|  */ |  */ | ||||||
| @ConfigurationProperties(PropertiesConstants.XSS) | @ConfigurationProperties(PropertiesConstants.XSS) | ||||||
| public class XssProperties { | public class XssProperties { | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 是否启用Xss |      * 是否启用 XSS 过滤 | ||||||
|      */ |      */ | ||||||
|     private boolean enabled = true; |     private boolean enabled = true; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 拦截的路由,默认为空 |      * 拦截路由(默认为空) | ||||||
|  |      * | ||||||
|  |      * <p> | ||||||
|  |      * 当拦截的路由配置不为空,则根据该配置执行过滤 | ||||||
|  |      * </p> | ||||||
|      */ |      */ | ||||||
|     private List<String> pathPatterns = new ArrayList<>(); |     private List<String> includePatterns = new ArrayList<>(); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 放行的路由,默认为空 |      * 放行路由(默认为空) | ||||||
|      */ |      */ | ||||||
|     private List<String> pathExcludePatterns = new ArrayList<>(); |     private List<String> excludePatterns = new ArrayList<>(); | ||||||
|  |  | ||||||
|     public boolean isEnabled() { |     public boolean isEnabled() { | ||||||
|         return enabled; |         return enabled; | ||||||
| @@ -53,20 +58,19 @@ public class XssProperties { | |||||||
|         this.enabled = enabled; |         this.enabled = enabled; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public List<String> getPathPatterns() { |     public List<String> getIncludePatterns() { | ||||||
|         return pathPatterns; |         return includePatterns; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setPathPatterns(List<String> pathPatterns) { |     public void setIncludePatterns(List<String> includePatterns) { | ||||||
|         this.pathPatterns = pathPatterns; |         this.includePatterns = includePatterns; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public List<String> getPathExcludePatterns() { |     public List<String> getExcludePatterns() { | ||||||
|         return pathExcludePatterns; |         return excludePatterns; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setPathExcludePatterns(List<String> pathExcludePatterns) { |     public void setExcludePatterns(List<String> excludePatterns) { | ||||||
|         this.pathExcludePatterns = pathExcludePatterns; |         this.excludePatterns = excludePatterns; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -31,10 +31,10 @@ import java.io.IOException; | |||||||
| import java.io.StringReader; | import java.io.StringReader; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 针对XssServletRequest进行过滤的包装类 |  * 针对 XssServletRequest 进行过滤的包装类 | ||||||
|  * |  * | ||||||
|  * @author whh |  * @author whh | ||||||
|  * @since 1.0.0 |  * @since 2.0.0 | ||||||
|  */ |  */ | ||||||
| public class XssServletRequestWrapper extends HttpServletRequestWrapper { | public class XssServletRequestWrapper extends HttpServletRequestWrapper { | ||||||
|  |  | ||||||
| @@ -102,6 +102,7 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper { | |||||||
|     static ServletInputStream getServletInputStream(String body) { |     static ServletInputStream getServletInputStream(String body) { | ||||||
|         final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); |         final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); | ||||||
|         return new ServletInputStream() { |         return new ServletInputStream() { | ||||||
|  |             @Override | ||||||
|             public int read() { |             public int read() { | ||||||
|                 return byteArrayInputStream.read(); |                 return byteArrayInputStream.read(); | ||||||
|             } |             } | ||||||
| @@ -118,9 +119,8 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper { | |||||||
|  |  | ||||||
|             @Override |             @Override | ||||||
|             public void setReadListener(ReadListener readListener) { |             public void setReadListener(ReadListener readListener) { | ||||||
|  |                 // 设置监听器 | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user