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 282184b3b3..cb24811f5c 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 @@ -431,14 +431,20 @@ public class StrictHttpFirewall implements HttpFirewall { if (!isNormalized(request)) { throw new RequestRejectedException("The request was rejected because the URL was not normalized."); } - String requestUri = request.getRequestURI(); - if (!containsOnlyPrintableAsciiCharacters(requestUri)) { - throw new RequestRejectedException( - "The requestURI was rejected because it can only contain printable ASCII characters."); - } + rejectNonPrintableAsciiCharactersInFieldName(request.getRequestURI(), "requestURI"); + rejectNonPrintableAsciiCharactersInFieldName(request.getServletPath(), "servletPath"); + rejectNonPrintableAsciiCharactersInFieldName(request.getPathInfo(), "pathInfo"); + rejectNonPrintableAsciiCharactersInFieldName(request.getContextPath(), "contextPath"); return new StrictFirewalledRequest(request); } + private void rejectNonPrintableAsciiCharactersInFieldName(String toCheck, String propertyName) { + if (!containsOnlyPrintableAsciiCharacters(toCheck)) { + throw new RequestRejectedException(String.format( + "The %s was rejected because it can only contain printable ASCII characters.", propertyName)); + } + } + private void rejectForbiddenHttpMethod(HttpServletRequest request) { if (this.allowedHttpMethods == ALLOW_ANY_HTTP_METHOD) { return; @@ -526,6 +532,9 @@ public class StrictHttpFirewall implements HttpFirewall { } private static boolean containsOnlyPrintableAsciiCharacters(String uri) { + if (uri == null) { + return true; + } int length = uri.length(); for (int i = 0; i < length; i++) { char ch = uri.charAt(i); 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 3ca722f9bd..154b5a53cf 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 @@ -364,6 +364,34 @@ public class StrictHttpFirewallTests { .isThrownBy(() -> this.firewall.getFirewalledRequest(this.request)); } + @Test + public void getFirewalledRequestWhenContainsLineFeedThenException() { + this.request.setRequestURI("/something\n/"); + assertThatExceptionOfType(RequestRejectedException.class) + .isThrownBy(() -> this.firewall.getFirewalledRequest(this.request)); + } + + @Test + public void getFirewalledRequestWhenServletPathContainsLineFeedThenException() { + this.request.setServletPath("/something\n/"); + assertThatExceptionOfType(RequestRejectedException.class) + .isThrownBy(() -> this.firewall.getFirewalledRequest(this.request)); + } + + @Test + public void getFirewalledRequestWhenContainsCarriageReturnThenException() { + this.request.setRequestURI("/something\r/"); + assertThatExceptionOfType(RequestRejectedException.class) + .isThrownBy(() -> this.firewall.getFirewalledRequest(this.request)); + } + + @Test + public void getFirewalledRequestWhenServletPathContainsCarriageReturnThenException() { + this.request.setServletPath("/something\r/"); + assertThatExceptionOfType(RequestRejectedException.class) + .isThrownBy(() -> this.firewall.getFirewalledRequest(this.request)); + } + /** * On WebSphere 8.5 a URL like /context-root/a/b;%2f1/c can bypass a rule on /a/b/c * because the pathInfo is /a/b;/1/c which ends up being /a/b/1/c while Spring MVC