🔒 Fixing security issues. #1932 启动支持 @Inner 路径安全性检测

This commit is contained in:
冷冷 committed 2020-10-16 11:04:16 +08:00
1 parent bdf0824e30
commit 7f651b4667
2 files changed
+64 -9

No files matched your search

@@ -25,6 +25,11 @@ package com.pig4cloud.pigx.common.core.constant;
*/
public interface SecurityConstants {
/**
* 启动时是否检查Inner注解安全性
*/
boolean INNER_CHECK = true;
/**
* 刷新
*/
@@ -21,6 +21,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.security.annotation.Inner;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -34,7 +35,8 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
@@ -59,6 +61,8 @@ import java.util.stream.Collectors;
@ConfigurationProperties(prefix = "security.oauth2.client")
public class PermitAllUrlResolver implements InitializingBean {
private static final PathMatcher PATHMATCHER = new AntPathMatcher();
private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
private final WebApplicationContext applicationContext;
@@ -81,9 +85,8 @@ public class PermitAllUrlResolver implements InitializingBean {
// 2. 当类上不包含 @Inner 注解则获取该方法的注解
if (controller == null) {
Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class);
RequestMapping rq = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), RequestMapping.class);
Optional.ofNullable(method).ifPresent(
inner -> info.getPatternsCondition().getPatterns().forEach(url -> this.filterPath(url, rq)));
inner -> info.getPatternsCondition().getPatterns().forEach(url -> this.filterPath(url, info, map)));
continue;
}
@@ -92,8 +95,7 @@ public class PermitAllUrlResolver implements InitializingBean {
Method[] methods = beanType.getDeclaredMethods();
Method method = handlerMethod.getMethod();
if (ArrayUtil.contains(methods, method)) {
RequestMapping rq = AnnotationUtils.findAnnotation(method, RequestMapping.class);
info.getPatternsCondition().getPatterns().forEach(url -> filterPath(url, rq));
info.getPatternsCondition().getPatterns().forEach(url -> filterPath(url, info, map));
}
}
@@ -102,14 +104,21 @@ public class PermitAllUrlResolver implements InitializingBean {
/**
* 过滤 Inner 设置
*
* <p>0. 暴露安全检查</p>
* <p>1. 路径转换: 如果为restful(/xx/{xx}) --> /xx/* ant 表达式</p>
* <p> 2. 构建表达式:允许暴露的接口|允许暴露的方法类型,允许暴露的方法类型 URL|GET,POST,DELETE,PUT</p>
*
* @param url mapping路径
* @param rq 请求犯法
* @param url mapping路径
* @param info 请求犯法
* @param map 路由映射信息
*/
private void filterPath(String url, RequestMapping rq) {
List<String> methodList = Arrays.stream(rq.method()).map(RequestMethod::name).collect(Collectors.toList());
private void filterPath(String url, RequestMappingInfo info, Map<RequestMappingInfo, HandlerMethod> map) {
// 安全检查
if (SecurityConstants.INNER_CHECK){
security(url, info, map);
}
List<String> methodList = info.getMethodsCondition().getMethods().stream().map(RequestMethod::name).collect(Collectors.toList());
String resultUrl = ReUtil.replaceAll(url, PATTERN, "*");
if (CollUtil.isEmpty(methodList)) {
ignoreUrls.add(resultUrl);
@@ -118,6 +127,47 @@ public class PermitAllUrlResolver implements InitializingBean {
}
}
/**
* 针对Pathvariable 请求安全检查。增加启动好使影响启动效率 请注意
*
* @param url 接口路径
* @param rq 当前请求的元信息
* @param map springmvc 接口列表
*/
private void security(String url, RequestMappingInfo rq, Map<RequestMappingInfo, HandlerMethod> map) {
// 判断 URL 是否是 rest path 形式
if (!StrUtil.containsAny(url, StrUtil.DELIM_START, StrUtil.DELIM_END)) {
return;
}
for (RequestMappingInfo info : map.keySet()) {
Set<RequestMethod> methods = info.getMethodsCondition().getMethods();
// 如果请求方法不匹配跳过
if (!CollUtil.containsAny(methods, rq.getMethodsCondition().getMethods())) {
continue;
}
// 如果请求方法路径匹配
Set<String> patterns = info.getPatternsCondition().getPatterns();
for (String pattern : patterns) {
// 跳过自身
if (StrUtil.equals(url, pattern)) {
continue;
}
if (PATHMATCHER.match(url, pattern)) {
HandlerMethod rqMethod = map.get(rq);
HandlerMethod infoMethod = map.get(info);
log.error("@Inner 标记接口 ==> {}.{} 使用不当,会额外暴露接口 ==> {}.{} 请知悉"
, rqMethod.getBeanType().getName()
, rqMethod.getMethod().getName()
, infoMethod.getBeanType().getName()
, infoMethod.getMethod().getName());
}
}
}
}
/**
* 获取对外暴露的URL,注册到 spring security
*