diff --git a/examples/boot2-example/pom.xml b/examples/boot2-example/pom.xml index 6357af9..286ed6f 100644 --- a/examples/boot2-example/pom.xml +++ b/examples/boot2-example/pom.xml @@ -9,7 +9,7 @@ dev.flyfish.validation.example flyfish-validation-boot2-example - 1.0.0 + 1.0.1-SNAPSHOT Flyfish Validation Boot 2 Example 8 @@ -18,7 +18,7 @@ dev.flyfish flyfish-validation-spring-boot2-starter - 1.0.0 + 1.0.1-SNAPSHOT org.springframework.boot diff --git a/examples/boot3-example/pom.xml b/examples/boot3-example/pom.xml index 8281208..659a77b 100644 --- a/examples/boot3-example/pom.xml +++ b/examples/boot3-example/pom.xml @@ -9,7 +9,7 @@ dev.flyfish.validation.example flyfish-validation-boot3-example - 1.0.0 + 1.0.1-SNAPSHOT Flyfish Validation Boot 3 Example 17 @@ -18,7 +18,7 @@ dev.flyfish flyfish-validation-spring-boot3-starter - 1.0.0 + 1.0.1-SNAPSHOT org.springframework.boot diff --git a/examples/boot4-example/pom.xml b/examples/boot4-example/pom.xml index ca5aa33..edd957c 100644 --- a/examples/boot4-example/pom.xml +++ b/examples/boot4-example/pom.xml @@ -9,7 +9,7 @@ dev.flyfish.validation.example flyfish-validation-boot4-example - 1.0.0 + 1.0.1-SNAPSHOT Flyfish Validation Boot 4 Example 17 @@ -18,7 +18,7 @@ dev.flyfish flyfish-validation-spring-boot4-starter - 1.0.0 + 1.0.1-SNAPSHOT org.springframework.boot diff --git a/flyfish-validation-bom/pom.xml b/flyfish-validation-bom/pom.xml index f541348..68569af 100644 --- a/flyfish-validation-bom/pom.xml +++ b/flyfish-validation-bom/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-bom pom diff --git a/flyfish-validation-core/pom.xml b/flyfish-validation-core/pom.xml index dc2ebb8..06ffb32 100644 --- a/flyfish-validation-core/pom.xml +++ b/flyfish-validation-core/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-core jar diff --git a/flyfish-validation-jakarta/pom.xml b/flyfish-validation-jakarta/pom.xml index 84de883..2c2798d 100644 --- a/flyfish-validation-jakarta/pom.xml +++ b/flyfish-validation-jakarta/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-jakarta jar diff --git a/flyfish-validation-javax/pom.xml b/flyfish-validation-javax/pom.xml index e1c8b3d..971fe09 100644 --- a/flyfish-validation-javax/pom.xml +++ b/flyfish-validation-javax/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-javax jar diff --git a/flyfish-validation-spring-boot2-autoconfigure/pom.xml b/flyfish-validation-spring-boot2-autoconfigure/pom.xml index 36d9787..cfd45ee 100644 --- a/flyfish-validation-spring-boot2-autoconfigure/pom.xml +++ b/flyfish-validation-spring-boot2-autoconfigure/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-spring-boot2-autoconfigure jar diff --git a/flyfish-validation-spring-boot2-starter/pom.xml b/flyfish-validation-spring-boot2-starter/pom.xml index 65b4250..836c0fd 100644 --- a/flyfish-validation-spring-boot2-starter/pom.xml +++ b/flyfish-validation-spring-boot2-starter/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-spring-boot2-starter jar diff --git a/flyfish-validation-spring-boot3-autoconfigure/pom.xml b/flyfish-validation-spring-boot3-autoconfigure/pom.xml index e2fb23e..ea480b6 100644 --- a/flyfish-validation-spring-boot3-autoconfigure/pom.xml +++ b/flyfish-validation-spring-boot3-autoconfigure/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-spring-boot3-autoconfigure jar diff --git a/flyfish-validation-spring-boot3-starter/pom.xml b/flyfish-validation-spring-boot3-starter/pom.xml index d562295..622c2da 100644 --- a/flyfish-validation-spring-boot3-starter/pom.xml +++ b/flyfish-validation-spring-boot3-starter/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-spring-boot3-starter jar diff --git a/flyfish-validation-spring-boot4-autoconfigure/pom.xml b/flyfish-validation-spring-boot4-autoconfigure/pom.xml index 63a7248..9f3d0b1 100644 --- a/flyfish-validation-spring-boot4-autoconfigure/pom.xml +++ b/flyfish-validation-spring-boot4-autoconfigure/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-spring-boot4-autoconfigure jar diff --git a/flyfish-validation-spring-boot4-starter/pom.xml b/flyfish-validation-spring-boot4-starter/pom.xml index 0ba7786..f42a09e 100644 --- a/flyfish-validation-spring-boot4-starter/pom.xml +++ b/flyfish-validation-spring-boot4-starter/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-spring-boot4-starter jar diff --git a/flyfish-validation-spring-support/pom.xml b/flyfish-validation-spring-support/pom.xml index dfa94ff..903e707 100644 --- a/flyfish-validation-spring-support/pom.xml +++ b/flyfish-validation-spring-support/pom.xml @@ -4,7 +4,7 @@ dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT flyfish-validation-spring-support jar diff --git a/flyfish-validation-spring-support/src/main/java/dev/flyfish/validation/spring/DefaultValidationRejectedValueSanitizer.java b/flyfish-validation-spring-support/src/main/java/dev/flyfish/validation/spring/DefaultValidationRejectedValueSanitizer.java index f455240..534a36e 100644 --- a/flyfish-validation-spring-support/src/main/java/dev/flyfish/validation/spring/DefaultValidationRejectedValueSanitizer.java +++ b/flyfish-validation-spring-support/src/main/java/dev/flyfish/validation/spring/DefaultValidationRejectedValueSanitizer.java @@ -5,6 +5,7 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import dev.flyfish.validation.api.ValidationError; @@ -20,6 +21,11 @@ public final class DefaultValidationRejectedValueSanitizer implements ValidationRejectedValueSanitizer { private static final int MAX_ATTRIBUTE_DEPTH = 4; + private static final String[] SENSITIVE_PATH_FRAGMENTS = { + "authorization", "cookie", "password", "passwd", "secret", "token", + "apikey", "accesskey", "privatekey", "credential", "sessionid", + "jsessionid", "otp", "cvv", "bankcard", "idcard" + }; private final boolean exposeRejectedValue; private final boolean exposeAttributes; @@ -40,7 +46,12 @@ public ValidationError sanitize(ValidationError error) { .propertyPath(error.getPropertyPath()) .severity(error.getSeverity()) .validator(error.getValidator()); - if (exposeRejectedValue) { + /* + * The general exposure switch is useful for harmless fields, but it must never override + * the sensitive-field denylist. Otherwise a diagnostics setting could reflect passwords, + * tokens, or credentials into API responses and logs without any warning at the call site. + */ + if (exposeRejectedValue && !isSensitivePath(error.getPropertyPath())) { builder.rejectedValue(simpleValue(error.getRejectedValue(), 0)); } if (exposeAttributes) { @@ -53,6 +64,24 @@ public ValidationError sanitize(ValidationError error) { return builder.build(); } + private static boolean isSensitivePath(String propertyPath) { + if (propertyPath == null || propertyPath.isEmpty()) { + return false; + } + String normalized = propertyPath.toLowerCase(Locale.ROOT) + .replace("_", "") + .replace("-", "") + .replace(".", "") + .replace("[", "") + .replace("]", ""); + for (String fragment : SENSITIVE_PATH_FRAGMENTS) { + if (normalized.contains(fragment)) { + return true; + } + } + return false; + } + private static Object simpleValue(Object value, int depth) { if (value == null || value instanceof String || value instanceof Number || value instanceof Boolean diff --git a/flyfish-validation-spring-support/src/test/java/dev/flyfish/validation/spring/DefaultValidationRejectedValueSanitizerTest.java b/flyfish-validation-spring-support/src/test/java/dev/flyfish/validation/spring/DefaultValidationRejectedValueSanitizerTest.java new file mode 100644 index 0000000..dd55b29 --- /dev/null +++ b/flyfish-validation-spring-support/src/test/java/dev/flyfish/validation/spring/DefaultValidationRejectedValueSanitizerTest.java @@ -0,0 +1,35 @@ +package dev.flyfish.validation.spring; + +import dev.flyfish.validation.api.ValidationError; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** 敏感字段即使启用 rejected value 诊断开关也必须保持脱敏。 */ +class DefaultValidationRejectedValueSanitizerTest { + + private final DefaultValidationRejectedValueSanitizer sanitizer = + new DefaultValidationRejectedValueSanitizer(true, false); + + @Test + void exposesRejectedValueForOrdinaryFieldsWhenExplicitlyEnabled() { + ValidationError error = error("displayName", "张三"); + + assertEquals("张三", sanitizer.sanitize(error).getRejectedValue()); + } + + @Test + void neverExposesSensitiveRejectedValues() { + // 离线兼容检查使用最小 JUnit API 桩;用标准等值断言保持测试语义且不扩大桩接口。 + assertEquals(null, sanitizer.sanitize(error("password", "Plaintext-Secret")).getRejectedValue()); + assertEquals(null, sanitizer.sanitize(error("credentials.clientSecret", "secret")).getRejectedValue()); + assertEquals(null, sanitizer.sanitize(error("oauth.access_token", "token")).getRejectedValue()); + } + + private static ValidationError error(String propertyPath, Object rejectedValue) { + return ValidationError.builder("INVALID", "校验失败") + .propertyPath(propertyPath) + .rejectedValue(rejectedValue) + .build(); + } +} diff --git a/pom.xml b/pom.xml index 7d3d094..61de673 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 dev.flyfish flyfish-validation-parent - 1.0.0 + 1.0.1-SNAPSHOT pom Flyfish Validation 面向 Java 8-21 与 Spring Boot 2/3/4 的企业级验证增强库