diff --git a/web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java b/web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java index 585ecd503f1..dfb0d73bfb3 100644 --- a/web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java +++ b/web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -130,9 +130,13 @@ public class StrictHttpFirewall implements HttpFirewall { private static final Predicate ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE = ( s) -> ASSIGNED_AND_NOT_ISO_CONTROL_PATTERN.matcher(s).matches(); + private static final Pattern HEADER_VALUE_PATTERN = Pattern.compile("[\\p{IsAssigned}&&[[^\\p{IsControl}]||\\t]]*"); + + private static final Predicate HEADER_VALUE_PREDICATE = (s) -> HEADER_VALUE_PATTERN.matcher(s).matches(); + private Predicate allowedHeaderNames = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE; - private Predicate allowedHeaderValues = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE; + private Predicate allowedHeaderValues = HEADER_VALUE_PREDICATE; private Predicate allowedParameterNames = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE; diff --git a/web/src/test/java/org/springframework/security/web/firewall/StrictHttpFirewallTests.java b/web/src/test/java/org/springframework/security/web/firewall/StrictHttpFirewallTests.java index 6368faafe3d..98b398a91a9 100644 --- a/web/src/test/java/org/springframework/security/web/firewall/StrictHttpFirewallTests.java +++ b/web/src/test/java/org/springframework/security/web/firewall/StrictHttpFirewallTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -781,6 +781,13 @@ public void getFirewalledRequestGetHeaderWhenControlCharacterInHeaderValueThenEx assertThatExceptionOfType(RequestRejectedException.class).isThrownBy(() -> request.getHeader("Something")); } + @Test + public void getFirewalledRequestGetHeaderWhenHorizontalTabInHeaderValueThenNoException() { + this.request.addHeader("Something", "tab\tvalue"); + HttpServletRequest request = this.firewall.getFirewalledRequest(this.request); + assertThat(request.getHeader("Something")).isEqualTo("tab\tvalue"); + } + @Test public void getFirewalledRequestGetHeaderWhenUndefinedCharacterInHeaderValueThenException() { this.request.addHeader("Something", "bad\uFFFEvalue");