mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-12 14:57:10 +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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -34,7 +34,7 @@ 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