【validator】新增xss安全模块,修改validator的相关包路径

pull/3/head
fengshuonan 2021-01-13 23:47:17 +08:00
parent 1178eee90f
commit 698a2bb804
18 changed files with 442 additions and 10 deletions

View File

@ -19,6 +19,7 @@
<module>validator-api</module>
<module>validator-sdk-count</module>
<module>validator-sdk-black-white</module>
<module>validator-sdk-xss</module>
<module>validator-business-count</module>
<module>validator-spring-boot-starter</module>
</modules>

View File

@ -0,0 +1,16 @@
package cn.stylefeng.roses.kernel.validator.constants;
/**
* XSS
*
* @author fengshuonan
* @date 2021/1/13 23:35
*/
public interface XssConstants {
/**
*
*/
String DEFAULT_XSS_PATTERN = "/*";
}

View File

@ -0,0 +1,24 @@
package cn.stylefeng.roses.kernel.validator.exception;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.rule.abstracts.AbstractExceptionEnum;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.roses.kernel.validator.constants.ValidatorConstants;
/**
* XSS
*
* @author fengshuonan
* @date 2021/1/13 23:22
*/
public class XssFilterException extends ServiceException {
public XssFilterException(AbstractExceptionEnum exception, Object... params) {
super(ValidatorConstants.VALIDATOR_MODULE_NAME, exception.getErrorCode(), StrUtil.format(exception.getUserTip(), params));
}
public XssFilterException(AbstractExceptionEnum exception) {
super(ValidatorConstants.VALIDATOR_MODULE_NAME, exception);
}
}

View File

@ -0,0 +1,37 @@
package cn.stylefeng.roses.kernel.validator.exception.enums;
import cn.stylefeng.roses.kernel.rule.abstracts.AbstractExceptionEnum;
import cn.stylefeng.roses.kernel.rule.constants.RuleConstants;
import cn.stylefeng.roses.kernel.validator.constants.ValidatorConstants;
import lombok.Getter;
/**
* XSS
*
* @author fengshuonan
* @date 2021/1/13 23:23
*/
@Getter
public enum XssFilterExceptionEnum implements AbstractExceptionEnum {
/**
* XSS
*/
CONFIG_IS_NULL(RuleConstants.BUSINESS_ERROR_TYPE_CODE + ValidatorConstants.VALIDATOR_EXCEPTION_STEP_CODE + "11", "XSS初始化配置为空请检查XSS过滤器配置是否正确");
/**
*
*/
private final String errorCode;
/**
*
*/
private final String userTip;
XssFilterExceptionEnum(String errorCode, String userTip) {
this.errorCode = errorCode;
this.userTip = userTip;
}
}

View File

@ -0,0 +1,47 @@
package cn.stylefeng.roses.kernel.validator.expander;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.config.api.context.ConfigContext;
import java.util.ArrayList;
import java.util.List;
import static cn.stylefeng.roses.kernel.validator.constants.XssConstants.DEFAULT_XSS_PATTERN;
/**
* XSS
*
* @author fengshuonan
* @date 2021/1/13 23:21
*/
public class XssConfigExpander {
/**
* XSSurl
*
* @author fengshuonan
* @date 2021/1/13 23:21
*/
public static String[] getUrlPatterns() {
String xssUrlIncludes = ConfigContext.me().getSysConfigValueWithDefault("SYS_XSS_URL_INCLUDES", String.class, DEFAULT_XSS_PATTERN);
List<String> split = StrUtil.split(xssUrlIncludes, ',');
return ArrayUtil.toArray(split, String.class);
}
/**
* XSSurl
*
* @author fengshuonan
* @date 2021/1/13 23:21
*/
public static List<String> getUrlExclusion() {
String noneSecurityUrls = ConfigContext.me().getSysConfigValueWithDefault("SYS_XSS_URL_EXCLUSIONS", String.class, "");
if (StrUtil.isEmpty(noneSecurityUrls)) {
return new ArrayList<>();
} else {
return StrUtil.split(noneSecurityUrls, ',');
}
}
}

View File

@ -0,0 +1 @@
XSS过滤器有效防止XSS攻击

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>kernel-d-validator</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>validator-sdk-xss</artifactId>
<dependencies>
<!--校验模块的api-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>validator-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,51 @@
package cn.stylefeng.roses.kemel.xss;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kemel.xss.prop.XssProperties;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* XSS使 XssHttpServletRequestWrapper HttpServletRequest
* <p>
* param
*
* @author fengshuonan
* @date 2021/1/13 22:45
*/
public class XssFilter implements Filter {
public static final String FILTER_NAME = "GUNS_XSS_FILTER";
private final XssProperties xssProperties;
public XssFilter(XssProperties xssProperties) {
this.xssProperties = xssProperties;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String servletPath = httpServletRequest.getServletPath();
String contextPath = httpServletRequest.getContextPath();
AntPathMatcher antPathMatcher = new AntPathMatcher();
// 如果当前servlet path排除在外则放行
if (xssProperties != null &&
ObjectUtil.isNotEmpty(xssProperties.getUrlExclusion())) {
for (String exclusion : xssProperties.getUrlExclusion()) {
if (antPathMatcher.match(contextPath + exclusion, servletPath)) {
chain.doFilter(request, response);
return;
}
}
}
// 对原有request对象进行包装
chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);
}
}

View File

@ -0,0 +1,73 @@
package cn.stylefeng.roses.kemel.xss;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HtmlUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* HttpServletRequestxss
*
* @author fengshuonan
* @date 2021/1/13 22:50
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
}
/**
* param
*
* @author fengshuonan
* @date 2021/1/13 22:52
*/
public String[] getParameterValues(String parameter) {
// 获取所有参数
String[] values = super.getParameterValues(parameter);
if (ObjectUtil.isEmpty(values)) {
return values;
}
// 针对每一个string参数进行过滤
String[] encodedValues = new String[values.length];
for (int i = 0; i < values.length; i++) {
encodedValues[i] = HtmlUtil.filter(values[i]);
}
return encodedValues;
}
/**
* param
*
* @author fengshuonan
* @date 2021/1/13 22:52
*/
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (ObjectUtil.isEmpty(value)) {
return value;
}
return HtmlUtil.filter(value);
}
/**
* header
*
* @author fengshuonan
* @date 2021/1/13 22:53
*/
public String getHeader(String name) {
String value = super.getHeader(name);
if (ObjectUtil.isEmpty(value)) {
return value;
}
return HtmlUtil.filter(value);
}
}

View File

@ -0,0 +1,47 @@
package cn.stylefeng.roses.kemel.xss;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HtmlUtil;
import cn.stylefeng.roses.kemel.xss.prop.XssProperties;
import cn.stylefeng.roses.kernel.rule.util.HttpServletUtil;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.springframework.util.AntPathMatcher;
import java.io.IOException;
/**
* jacksonxss
*
* @author fengshuonan
* @date 2021/1/13 22:56
*/
public class XssJacksonDeserializer extends JsonDeserializer<String> {
private final XssProperties xssProperties;
public XssJacksonDeserializer(XssProperties xssProperties) {
this.xssProperties = xssProperties;
}
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
String servletPath = HttpServletUtil.getRequest().getServletPath();
String contextPath = HttpServletUtil.getRequest().getContextPath();
AntPathMatcher antPathMatcher = new AntPathMatcher();
// 如果当前servlet path排除在外则放行
if (xssProperties != null &&
ObjectUtil.isNotEmpty(xssProperties.getUrlExclusion())) {
for (String exclusion : xssProperties.getUrlExclusion()) {
if (antPathMatcher.match(contextPath + exclusion, servletPath)) {
return jsonParser.getText();
}
}
}
return HtmlUtil.filter(jsonParser.getText());
}
}

View File

@ -0,0 +1,26 @@
package cn.stylefeng.roses.kemel.xss.prop;
import lombok.Data;
import java.util.List;
/**
* Xss
*
* @author fengshuonan
* @date 2021/1/13 22:46
*/
@Data
public class XssProperties {
/**
* xssservletfilterurlPattern
*/
private String[] urlPatterns;
/**
* xssurlANT
*/
private List<String> urlExclusion;
}

View File

@ -38,6 +38,13 @@
<version>1.0.0</version>
</dependency>
<!--XSS安全过滤器-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>validator-sdk-xss</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>

View File

@ -1,7 +1,7 @@
package cn.stylefeng.roses.kernel.validator.starter.resolver;
package cn.stylefeng.roses.kernel.validator.starter;
import cn.stylefeng.roses.kernel.validator.starter.web.GunsValidator;
import cn.stylefeng.roses.kernel.validator.starter.web.ValidatorRequestResponseBodyMethodProcessor;
import cn.stylefeng.roses.kernel.validator.starter.mvc.GunsValidator;
import cn.stylefeng.roses.kernel.validator.starter.mvc.GunsValidatorRequestResponseBodyMethodProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.context.annotation.Bean;
@ -23,7 +23,7 @@ import java.util.Objects;
*/
@Configuration
@AutoConfigureBefore(ValidationAutoConfiguration.class)
public class MethodArgumentResolver {
public class MethodArgumentResolverAutoConfiguration {
@Resource
private RequestMappingHandlerAdapter adapter;
@ -48,7 +48,7 @@ public class MethodArgumentResolver {
@PostConstruct
public void injectSelfMethodArgumentResolver() {
List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
argumentResolvers.add(new ValidatorRequestResponseBodyMethodProcessor(adapter.getMessageConverters()));
argumentResolvers.add(new GunsValidatorRequestResponseBodyMethodProcessor(adapter.getMessageConverters()));
argumentResolvers.addAll(Objects.requireNonNull(adapter.getArgumentResolvers()));
adapter.setArgumentResolvers(argumentResolvers);
}

View File

@ -0,0 +1,66 @@
package cn.stylefeng.roses.kernel.validator.starter;
import cn.stylefeng.roses.kemel.xss.XssFilter;
import cn.stylefeng.roses.kemel.xss.XssJacksonDeserializer;
import cn.stylefeng.roses.kemel.xss.prop.XssProperties;
import cn.stylefeng.roses.kernel.validator.expander.XssConfigExpander;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
/**
* XSS
*
* @author fengshuonan
* @date 2021/1/13 23:05
*/
@Configuration
public class XssFilterAutoConfiguration {
/**
* XSS Filterparam
*
* @author fengshuonan
* @date 2021/1/13 23:09
*/
@Bean
public FilterRegistrationBean<XssFilter> xssFilterFilterRegistrationBean() {
XssProperties properties = createProperties();
FilterRegistrationBean<XssFilter> xssFilterFilterRegistrationBean = new FilterRegistrationBean<>();
xssFilterFilterRegistrationBean.setFilter(new XssFilter(properties));
xssFilterFilterRegistrationBean.addUrlPatterns(properties.getUrlPatterns());
xssFilterFilterRegistrationBean.setName(XssFilter.FILTER_NAME);
xssFilterFilterRegistrationBean.setOrder(HIGHEST_PRECEDENCE);
return xssFilterFilterRegistrationBean;
}
/**
* XSSjsonjson
*
* @author fengshuonan
* @date 2021/1/13 23:09
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer xssJackson2ObjectMapperBuilderCustomizer() {
return jacksonObjectMapperBuilder ->
jacksonObjectMapperBuilder.deserializerByType(String.class, new XssJacksonDeserializer(new XssProperties()));
}
/**
* xss
*
* @author fengshuonan
* @date 2021/1/13 23:13
*/
private XssProperties createProperties() {
XssProperties xssProperties = new XssProperties();
xssProperties.setUrlPatterns(XssConfigExpander.getUrlPatterns());
xssProperties.setUrlExclusion(XssConfigExpander.getUrlExclusion());
return xssProperties;
}
}

View File

@ -1,4 +1,4 @@
package cn.stylefeng.roses.kernel.validator.starter.web;
package cn.stylefeng.roses.kernel.validator.starter.mvc;
import cn.stylefeng.roses.kernel.validator.context.RequestGroupContext;
import lombok.extern.slf4j.Slf4j;

View File

@ -1,4 +1,4 @@
package cn.stylefeng.roses.kernel.validator.starter.web;
package cn.stylefeng.roses.kernel.validator.starter.mvc;
import cn.stylefeng.roses.kernel.validator.context.RequestParamContext;
import org.springframework.core.Conventions;
@ -21,9 +21,9 @@ import java.util.List;
* @author fengshuonan
* @date 2020/8/21 20:51
*/
public class ValidatorRequestResponseBodyMethodProcessor extends RequestResponseBodyMethodProcessor {
public class GunsValidatorRequestResponseBodyMethodProcessor extends RequestResponseBodyMethodProcessor {
public ValidatorRequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
public GunsValidatorRequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
super(converters);
}

View File

@ -0,0 +1,4 @@
/**
* spring mvc便 RequestGroupContext
*/
package cn.stylefeng.roses.kernel.validator.starter.mvc;

View File

@ -1,3 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.stylefeng.roses.kernel.validator.starter.ValidatorAutoConfiguration,\
cn.stylefeng.roses.kernel.validator.starter.resolver.MethodArgumentResolver
cn.stylefeng.roses.kernel.validator.starter.MethodArgumentResolverAutoConfiguration,\
cn.stylefeng.roses.kernel.validator.starter.XssFilterAutoConfiguration