瀏覽代碼

Publish Constants for Firewall Header and Parameter Predicates

Introduced public static final Predicates for allowed header names,
header values, parameter names, and parameter values for building
expressions.

Closes gh-13639
baezzys 1 年之前
父節點
當前提交
4169c0cf36

+ 13 - 4
web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java

@@ -75,6 +75,7 @@ import org.springframework.util.Assert;
  *
  * @author Rob Winch
  * @author Eddú Meléndez
+ * @author Jinwoo Bae
  * @since 4.2.4
  * @see DefaultHttpFirewall
  */
@@ -134,13 +135,21 @@ public class StrictHttpFirewall implements HttpFirewall {
 
 	private static final Predicate<String> HEADER_VALUE_PREDICATE = (s) -> HEADER_VALUE_PATTERN.matcher(s).matches();
 
-	private Predicate<String> allowedHeaderNames = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
+	private Predicate<String> allowedHeaderNames = ALLOWED_HEADER_NAMES;
 
-	private Predicate<String> allowedHeaderValues = HEADER_VALUE_PREDICATE;
+	public static final Predicate<String> ALLOWED_HEADER_NAMES = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
 
-	private Predicate<String> allowedParameterNames = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
+	private Predicate<String> allowedHeaderValues = ALLOWED_HEADER_VALUES;
 
-	private Predicate<String> allowedParameterValues = (value) -> true;
+	public static final Predicate<String> ALLOWED_HEADER_VALUES = HEADER_VALUE_PREDICATE;
+
+	private Predicate<String> allowedParameterNames = ALLOWED_PARAMETER_NAMES;
+
+	public static final Predicate<String> ALLOWED_PARAMETER_NAMES = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
+
+	private Predicate<String> allowedParameterValues = ALLOWED_PARAMETER_VALUES;
+
+	public static final Predicate<String> ALLOWED_PARAMETER_VALUES = (value) -> true;
 
 	public StrictHttpFirewall() {
 		urlBlocklistsAddAll(FORBIDDEN_SEMICOLON);

+ 38 - 0
web/src/test/java/org/springframework/security/web/firewall/StrictHttpFirewallTests.java

@@ -31,6 +31,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 /**
  * @author Rob Winch
  * @author Eddú Meléndez
+ * @author Jinwoo Bae
  */
 public class StrictHttpFirewallTests {
 
@@ -723,6 +724,14 @@ public class StrictHttpFirewallTests {
 		assertThatExceptionOfType(RequestRejectedException.class).isThrownBy(() -> request.getHeader("bad name"));
 	}
 
+	@Test
+	public void getFirewalledRequestWhenHeaderNameNotAllowedWithAugmentedHeaderNamesThenException() {
+		this.firewall
+			.setAllowedHeaderNames(StrictHttpFirewall.ALLOWED_HEADER_NAMES.and((name) -> !name.equals("bad name")));
+		HttpServletRequest request = this.firewall.getFirewalledRequest(this.request);
+		assertThatExceptionOfType(RequestRejectedException.class).isThrownBy(() -> request.getHeader("bad name"));
+	}
+
 	@Test
 	public void getFirewalledRequestGetHeaderWhenNotAllowedHeaderValueThenException() {
 		this.request.addHeader("good name", "bad value");
@@ -731,6 +740,15 @@ public class StrictHttpFirewallTests {
 		assertThatExceptionOfType(RequestRejectedException.class).isThrownBy(() -> request.getHeader("good name"));
 	}
 
+	@Test
+	public void getFirewalledRequestWhenHeaderValueNotAllowedWithAugmentedHeaderValuesThenException() {
+		this.request.addHeader("good name", "bad value");
+		this.firewall.setAllowedHeaderValues(
+				StrictHttpFirewall.ALLOWED_HEADER_VALUES.and((value) -> !value.equals("bad value")));
+		HttpServletRequest request = this.firewall.getFirewalledRequest(this.request);
+		assertThatExceptionOfType(RequestRejectedException.class).isThrownBy(() -> request.getHeader("good name"));
+	}
+
 	@Test
 	public void getFirewalledRequestGetDateHeaderWhenControlCharacterInHeaderNameThenException() {
 		this.request.addHeader("Bad\0Name", "some value");
@@ -840,6 +858,16 @@ public class StrictHttpFirewallTests {
 			.isThrownBy(() -> request.getParameterValues("Something"));
 	}
 
+	@Test
+	public void getFirewalledRequestWhenParameterValueNotAllowedWithAugmentedParameterValuesThenException() {
+		this.request.addParameter("Something", "bad value");
+		this.firewall.setAllowedParameterValues(
+				StrictHttpFirewall.ALLOWED_PARAMETER_VALUES.and((value) -> !value.equals("bad value")));
+		HttpServletRequest request = this.firewall.getFirewalledRequest(this.request);
+		assertThatExceptionOfType(RequestRejectedException.class)
+			.isThrownBy(() -> request.getParameterValues("Something"));
+	}
+
 	@Test
 	public void getFirewalledRequestGetParameterValuesWhenNotAllowedInParameterNameThenException() {
 		this.firewall.setAllowedParameterNames((value) -> !value.equals("bad name"));
@@ -849,6 +877,16 @@ public class StrictHttpFirewallTests {
 			.isThrownBy(() -> request.getParameterValues("bad name"));
 	}
 
+	@Test
+	public void getFirewalledRequestWhenParameterNameNotAllowedWithAugmentedParameterNamesThenException() {
+		this.request.addParameter("bad name", "good value");
+		this.firewall.setAllowedParameterNames(
+				StrictHttpFirewall.ALLOWED_PARAMETER_NAMES.and((value) -> !value.equals("bad name")));
+		HttpServletRequest request = this.firewall.getFirewalledRequest(this.request);
+		assertThatExceptionOfType(RequestRejectedException.class)
+			.isThrownBy(() -> request.getParameterValues("bad name"));
+	}
+
 	// gh-9598
 	@Test
 	public void getFirewalledRequestGetParameterWhenNameIsNullThenIllegalArgumentException() {