From 7f651b466723c11feef3edb5be316a06280b56a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E5=86=B7?= Date: Fri, 16 Oct 2020 11:04:16 +0800 Subject: [PATCH] =?UTF-8?q?:lock:=20Fixing=20security=20issues.=20#1932=20?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=94=AF=E6=8C=81=20@Inner=20=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=AE=89=E5=85=A8=E6=80=A7=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/constant/SecurityConstants.java | 5 ++ .../component/PermitAllUrlResolver.java | 68 ++++++++++++++++--- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java index 13b1e8adc..57de181f5 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java @@ -25,6 +25,11 @@ package com.pig4cloud.pigx.common.core.constant; */ public interface SecurityConstants { + /** + * 启动时是否检查Inner注解安全性 + */ + boolean INNER_CHECK = true; + /** * 刷新 */ diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlResolver.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlResolver.java index b62131845..d98946f9a 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlResolver.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlResolver.java @@ -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 设置 * + *

0. 暴露安全检查

*

1. 路径转换: 如果为restful(/xx/{xx}) --> /xx/* ant 表达式

*

2. 构建表达式:允许暴露的接口|允许暴露的方法类型,允许暴露的方法类型 URL|GET,POST,DELETE,PUT

* - * @param url mapping路径 - * @param rq 请求犯法 + * @param url mapping路径 + * @param info 请求犯法 + * @param map 路由映射信息 */ - private void filterPath(String url, RequestMapping rq) { - List methodList = Arrays.stream(rq.method()).map(RequestMethod::name).collect(Collectors.toList()); + private void filterPath(String url, RequestMappingInfo info, Map map) { + // 安全检查 + if (SecurityConstants.INNER_CHECK){ + security(url, info, map); + } + + List 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 map) { + // 判断 URL 是否是 rest path 形式 + if (!StrUtil.containsAny(url, StrUtil.DELIM_START, StrUtil.DELIM_END)) { + return; + } + + for (RequestMappingInfo info : map.keySet()) { + Set methods = info.getMethodsCondition().getMethods(); + // 如果请求方法不匹配跳过 + if (!CollUtil.containsAny(methods, rq.getMethodsCondition().getMethods())) { + continue; + } + + // 如果请求方法路径匹配 + Set 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 *