mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-31 10:57:15 +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 配置 | ||||
| @@ -47,7 +47,7 @@ public class PropertiesConstants { | ||||
|     /** | ||||
|      * 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 配置 | ||||
|      */ | ||||
|     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() { | ||||
|     } | ||||
|   | ||||
| @@ -25,13 +25,13 @@ import org.slf4j.LoggerFactory; | ||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||||
| 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.web.servlet.FilterRegistrationBean; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Primary; | ||||
| import org.springframework.core.Ordered; | ||||
| 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 | ||||
|  */ | ||||
| @AutoConfiguration | ||||
| @ConditionalOnWebApplication | ||||
| @EnableConfigurationProperties(TraceProperties.class) | ||||
| @ConditionalOnProperty(prefix = PropertiesConstants.TRACE, name = PropertiesConstants.ENABLED, havingValue = "true") | ||||
| public class TraceAutoConfiguration { | ||||
| @@ -70,10 +71,9 @@ public class TraceAutoConfiguration { | ||||
|      * TLog 过滤器配置 | ||||
|      */ | ||||
|     @Bean | ||||
|     public FilterRegistrationBean<TLogServletFilter> filterRegistration() { | ||||
|     public FilterRegistrationBean<TLogServletFilter> tLogServletFilter() { | ||||
|         FilterRegistrationBean<TLogServletFilter> registration = new FilterRegistrationBean<>(); | ||||
|         registration.setFilter(new TLogServletFilter(traceProperties)); | ||||
|         registration.addUrlPatterns(StringConstants.PATH_PATTERN_CURRENT_DIR); | ||||
|         registration.setOrder(Ordered.HIGHEST_PRECEDENCE); | ||||
|         return registration; | ||||
|     } | ||||
|   | ||||
| @@ -25,18 +25,22 @@ import org.springframework.context.annotation.Bean; | ||||
| import top.charles7c.continew.starter.core.constant.PropertiesConstants; | ||||
|  | ||||
| /** | ||||
|  * XSS配置 | ||||
|  * XSS 过滤自动配置 | ||||
|  * | ||||
|  * @author whhya | ||||
|  * @since 1.0.0 | ||||
|  * @since 2.0.0 | ||||
|  */ | ||||
| @AutoConfiguration | ||||
| @ConditionalOnWebApplication | ||||
| @ConditionalOnProperty(prefix = PropertiesConstants.XSS, name = PropertiesConstants.ENABLED, havingValue = "true") | ||||
| @EnableConfigurationProperties(XssProperties.class) | ||||
| @ConditionalOnProperty(prefix = PropertiesConstants.XSS, name = PropertiesConstants.ENABLED, havingValue = "true") | ||||
| public class XssAutoConfiguration { | ||||
|  | ||||
|     /** | ||||
|      * XSS 过滤器配置 | ||||
|      */ | ||||
|     @Bean | ||||
|     public FilterRegistrationBean<XssFilter> XssFilter(XssProperties xssProperties) { | ||||
|     public FilterRegistrationBean<XssFilter> xssFilter(XssProperties xssProperties) { | ||||
|         FilterRegistrationBean<XssFilter> registrationBean = new FilterRegistrationBean<>(); | ||||
|         registrationBean.setFilter(new XssFilter(xssProperties)); | ||||
|         return registrationBean; | ||||
|   | ||||
| @@ -29,10 +29,10 @@ import java.io.IOException; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * xss过滤器 | ||||
|  * XSS 过滤器 | ||||
|  * | ||||
|  * @author whhya | ||||
|  * @since 1.0.0 | ||||
|  * @since 2.0.0 | ||||
|  */ | ||||
| public class XssFilter implements Filter { | ||||
|  | ||||
| @@ -53,58 +53,46 @@ public class XssFilter implements Filter { | ||||
|     public void doFilter(ServletRequest servletRequest, | ||||
|                          ServletResponse servletResponse, | ||||
|                          FilterChain filterChain) throws IOException, ServletException { | ||||
|         HttpServletRequest req = (HttpServletRequest) servletRequest; | ||||
|         //未开启xss过滤,则直接跳过 | ||||
|         if (!xssProperties.isEnabled()) { | ||||
|             filterChain.doFilter(req, servletResponse); | ||||
|         // 未开启 XSS 过滤,则直接跳过 | ||||
|         if (servletRequest instanceof HttpServletRequest request && xssProperties.isEnabled()) { | ||||
|             // 放行路由:忽略 XSS 过滤() | ||||
|             List<String> excludePatterns = xssProperties.getExcludePatterns(); | ||||
|             if (CollectionUtil.isNotEmpty(excludePatterns) && isMatchPath(request.getServletPath(), excludePatterns)) { | ||||
|                 filterChain.doFilter(request, servletResponse); | ||||
|                 return; | ||||
|             } | ||||
|             // 拦截路由:执行 XSS 过滤 | ||||
|             List<String> includePatterns = xssProperties.getIncludePatterns(); | ||||
|             if (CollectionUtil.isNotEmpty(includePatterns)) { | ||||
|                 if (isMatchPath(request.getServletPath(), includePatterns)) { | ||||
|                     filterChain.doFilter(new XssServletRequestWrapper(request), servletResponse); | ||||
|                 } else { | ||||
|                     filterChain.doFilter(request, servletResponse); | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|             // 默认:执行 XSS 过滤 | ||||
|             filterChain.doFilter(new XssServletRequestWrapper(request), servletResponse); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         //限定url地址 | ||||
|         List<String> pathPatterns = xssProperties.getPathPatterns(); | ||||
|  | ||||
|         //判断是否匹配需要忽略地址 | ||||
|         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 { | ||||
|                 filterChain.doFilter(req, servletResponse); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         //默认拦截 | ||||
|         filterChain.doFilter(new XssServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse); | ||||
|         filterChain.doFilter(servletRequest, servletResponse); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 判断数组中是否存在匹配的路径 | ||||
|      * | ||||
|      * @param requestURL   请求地址 | ||||
|      * @param requestUrl   请求地址 | ||||
|      * @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) { | ||||
|             PathPattern pathPattern = PathPatternParser.defaultInstance.parse(pattern); | ||||
|             PathContainer pathContainer = PathContainer.parsePath(requestURL); | ||||
|             boolean matches = pathPattern.matches(pathContainer); | ||||
|             if (matches) { | ||||
|             PathContainer pathContainer = PathContainer.parsePath(requestUrl); | ||||
|             if (pathPattern.matches(pathContainer)) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -23,27 +23,32 @@ import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * xss配置属性 | ||||
|  * XSS 过滤配置属性 | ||||
|  * | ||||
|  * @author whhya | ||||
|  * @since 1.0.0 | ||||
|  * @since 2.0.0 | ||||
|  */ | ||||
| @ConfigurationProperties(PropertiesConstants.XSS) | ||||
| public class XssProperties { | ||||
|  | ||||
|     /** | ||||
|      * 是否启用Xss | ||||
|      * 是否启用 XSS 过滤 | ||||
|      */ | ||||
|     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() { | ||||
|         return enabled; | ||||
| @@ -53,20 +58,19 @@ public class XssProperties { | ||||
|         this.enabled = enabled; | ||||
|     } | ||||
|  | ||||
|     public List<String> getPathPatterns() { | ||||
|         return pathPatterns; | ||||
|     public List<String> getIncludePatterns() { | ||||
|         return includePatterns; | ||||
|     } | ||||
|  | ||||
|     public void setPathPatterns(List<String> pathPatterns) { | ||||
|         this.pathPatterns = pathPatterns; | ||||
|     public void setIncludePatterns(List<String> includePatterns) { | ||||
|         this.includePatterns = includePatterns; | ||||
|     } | ||||
|  | ||||
|     public List<String> getPathExcludePatterns() { | ||||
|         return pathExcludePatterns; | ||||
|     public List<String> getExcludePatterns() { | ||||
|         return excludePatterns; | ||||
|     } | ||||
|  | ||||
|     public void setPathExcludePatterns(List<String> pathExcludePatterns) { | ||||
|         this.pathExcludePatterns = pathExcludePatterns; | ||||
|     public void setExcludePatterns(List<String> excludePatterns) { | ||||
|         this.excludePatterns = excludePatterns; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -31,10 +31,10 @@ import java.io.IOException; | ||||
| import java.io.StringReader; | ||||
|  | ||||
| /** | ||||
|  * 针对XssServletRequest进行过滤的包装类 | ||||
|  * 针对 XssServletRequest 进行过滤的包装类 | ||||
|  * | ||||
|  * @author whh | ||||
|  * @since 1.0.0 | ||||
|  * @since 2.0.0 | ||||
|  */ | ||||
| public class XssServletRequestWrapper extends HttpServletRequestWrapper { | ||||
|  | ||||
| @@ -102,6 +102,7 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper { | ||||
|     static ServletInputStream getServletInputStream(String body) { | ||||
|         final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); | ||||
|         return new ServletInputStream() { | ||||
|             @Override | ||||
|             public int read() { | ||||
|                 return byteArrayInputStream.read(); | ||||
|             } | ||||
| @@ -118,9 +119,8 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper { | ||||
|  | ||||
|             @Override | ||||
|             public void setReadListener(ReadListener readListener) { | ||||
|  | ||||
|                 // 设置监听器 | ||||
|             } | ||||
|  | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user