메뉴 내부 API 허용 IP 검증 로직 개선:
- IpAddressMatcher로 CIDR/와일드카드 지원 - 허용 IP 목록 설명 필드 추가 - RemoteAddr 정규화 로직 제거
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.eactive.apim.portal.djb.menu;
|
||||
|
||||
import com.eactive.apim.portal.common.util.IpAddressMatcher;
|
||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -12,11 +13,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 메뉴 캐시 내부 API — eapim-admin 의 reload 명령 수신용.
|
||||
@@ -24,6 +22,8 @@ import java.util.stream.Collectors;
|
||||
* <p>가드: PTL_PROPERTY {@code Portal / menu.internal.allow-ips} 허용 IP 목록
|
||||
* (기본 loopback) + X-Forwarded-For 동반 요청 거부
|
||||
* ({@code LegacyEncryptionMigrationController.assertLocalOnly} 모델).
|
||||
* 허용 목록은 {@link IpAddressMatcher} 규칙을 따라 정확 일치 외에
|
||||
* IPv4 CIDR({@code 172.30.1.0/24}) 과 옥텟 와일드카드({@code 172.30.*.*}) 를 지원한다.
|
||||
* CSRF 는 PortalConfigSecurity 에서 {@code /internal/menu/**} 예외 처리.</p>
|
||||
*
|
||||
* <pre>curl -X POST http://127.0.0.1:39130/internal/menu/reload</pre>
|
||||
@@ -37,6 +37,9 @@ public class MenuInternalController {
|
||||
static final String PROP_GROUP = "Portal";
|
||||
static final String PROP_ALLOW_IPS = "menu.internal.allow-ips";
|
||||
static final String DEFAULT_ALLOW_IPS = "127.0.0.1,::1";
|
||||
static final String PROP_ALLOW_IPS_DESCRIPTION =
|
||||
"메뉴 내부 API(리로드) 허용 IP 목록. 콤마(,)/세미콜론(;)/줄바꿈 구분, "
|
||||
+ "정확일치·IPv4 CIDR(172.30.1.0/24)·와일드카드(172.30.*.*) 지원";
|
||||
|
||||
private final MenuService menuService;
|
||||
private final PortalPropertyService portalPropertyService;
|
||||
@@ -66,16 +69,10 @@ public class MenuInternalController {
|
||||
* 그 경우에도 allowlist 검사로 차단된다. WebLogic WAR 배포에서는 원 소켓 IP 로 검사된다.)
|
||||
*/
|
||||
private boolean isAllowed(HttpServletRequest request) {
|
||||
String remote = canonicalize(request.getRemoteAddr());
|
||||
String remote = IpAddressMatcher.canonicalize(request.getRemoteAddr());
|
||||
boolean viaProxy = request.getHeader("X-Forwarded-For") != null;
|
||||
|
||||
Set<String> allowed = Arrays.stream(resolveAllowIps().split(","))
|
||||
.map(String::trim)
|
||||
.filter(ip -> !ip.isEmpty())
|
||||
.map(MenuInternalController::canonicalize)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (viaProxy || !allowed.contains(remote)) {
|
||||
if (viaProxy || !IpAddressMatcher.matches(resolveAllowIps(), remote)) {
|
||||
log.warn("메뉴 내부 API 차단 - remote: {}, viaProxy: {}", remote, viaProxy);
|
||||
return false;
|
||||
}
|
||||
@@ -85,15 +82,10 @@ public class MenuInternalController {
|
||||
private String resolveAllowIps() {
|
||||
try {
|
||||
return portalPropertyService.getOrCreateProperty(PROP_GROUP, PROP_ALLOW_IPS,
|
||||
DEFAULT_ALLOW_IPS, "메뉴 내부 API(리로드) 허용 IP 목록(콤마 구분)");
|
||||
DEFAULT_ALLOW_IPS, PROP_ALLOW_IPS_DESCRIPTION);
|
||||
} catch (Exception e) {
|
||||
log.warn("허용 IP 목록 조회 실패 - 기본값({}) 사용", DEFAULT_ALLOW_IPS, e);
|
||||
return DEFAULT_ALLOW_IPS;
|
||||
}
|
||||
}
|
||||
|
||||
/** IPv6 loopback 표기 통일 */
|
||||
private static String canonicalize(String ip) {
|
||||
return "0:0:0:0:0:0:0:1".equals(ip) ? "::1" : ip;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user