@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2012 - 2019 the original author or authors .
* Copyright 2012 - 202 1 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 .
@ -16,26 +16,27 @@
@@ -16,26 +16,27 @@
package org.springframework.security.web.firewall ;
import static org.assertj.core.api.Assertions.assertThatCode ;
import static org.assertj.core.api.Assertions.assertThatThrownBy ;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType ;
import static org.assertj.core.api.Assertions.fail ;
import java.util.Arrays ;
import java.util.List ;
import javax.servlet.http.HttpServletRequest ;
import org.junit.Test ;
import org.springframework.http.HttpMethod ;
import org.springframework.mock.web.MockHttpServletRequest ;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType ;
/ * *
* @author Rob Winch
* @author Eddú Meléndez
* /
public class StrictHttpFirewallTests {
public String [ ] unnormalizedPaths = { "/.." , "/./path/" , "/path/path/." , "/path/path//." , "./path/../path//." ,
"./path" , ".//path" , "." , "//path" , "//path/path" , "//path//path" , "/path//path" } ;
public String [ ] unnormalizedPaths = { "/.." , "/./path/" , "/path/path/." , "/path/path//." , "./path/../path//." ,
"./path" , ".//path" , "." , "//path" , "//path/path" , "//path//path" , "/path//path" } ;
private StrictHttpFirewall firewall = new StrictHttpFirewall ( ) ;
@ -44,32 +45,32 @@ public class StrictHttpFirewallTests {
@@ -44,32 +45,32 @@ public class StrictHttpFirewallTests {
@Test
public void getFirewalledRequestWhenInvalidMethodThenThrowsRequestRejectedException ( ) {
this . request . setMethod ( "INVALID" ) ;
assertThatThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) )
. isInstanceOf ( RequestRejectedException . class ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
// blocks XST attacks
@Test
public void getFirewalledRequestWhenTraceMethodThenThrowsRequestRejectedException ( ) {
this . request . setMethod ( HttpMethod . TRACE . name ( ) ) ;
assertThatThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) )
. isInstanceOf ( RequestRejectedException . class ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
// blocks XST attack if request is forwarded to a Microsoft IIS web server
public void getFirewalledRequestWhenTrackMethodThenThrowsRequestRejectedException ( ) {
this . request . setMethod ( "TRACK" ) ;
assertThatThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) )
. isInstanceOf ( RequestRejectedException . class ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
// HTTP methods are case sensitive
public void getFirewalledRequestWhenLowercaseGetThenThrowsRequestRejectedException ( ) {
this . request . setMethod ( "get" ) ;
assertThatThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) )
. isInstanceOf ( RequestRejectedException . class ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
@ -77,8 +78,7 @@ public class StrictHttpFirewallTests {
@@ -77,8 +78,7 @@ public class StrictHttpFirewallTests {
List < String > allowedMethods = Arrays . asList ( "DELETE" , "GET" , "HEAD" , "OPTIONS" , "PATCH" , "POST" , "PUT" ) ;
for ( String allowedMethod : allowedMethods ) {
this . request = new MockHttpServletRequest ( allowedMethod , "" ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) )
. doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
}
@ -86,8 +86,7 @@ public class StrictHttpFirewallTests {
@@ -86,8 +86,7 @@ public class StrictHttpFirewallTests {
public void getFirewalledRequestWhenInvalidMethodAndAnyMethodThenNoException ( ) {
this . firewall . setUnsafeAllowAnyHttpMethod ( true ) ;
this . request . setMethod ( "INVALID" ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) )
. doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test
@ -95,11 +94,8 @@ public class StrictHttpFirewallTests {
@@ -95,11 +94,8 @@ public class StrictHttpFirewallTests {
for ( String path : this . unnormalizedPaths ) {
this . request = new MockHttpServletRequest ( "GET" , "" ) ;
this . request . setRequestURI ( path ) ;
try {
this . firewall . getFirewalledRequest ( this . request ) ;
fail ( path + " is un-normalized" ) ;
} catch ( RequestRejectedException expected ) {
}
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
}
@ -108,11 +104,8 @@ public class StrictHttpFirewallTests {
@@ -108,11 +104,8 @@ public class StrictHttpFirewallTests {
for ( String path : this . unnormalizedPaths ) {
this . request = new MockHttpServletRequest ( "GET" , "" ) ;
this . request . setContextPath ( path ) ;
try {
this . firewall . getFirewalledRequest ( this . request ) ;
fail ( path + " is un-normalized" ) ;
} catch ( RequestRejectedException expected ) {
}
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
}
@ -121,11 +114,8 @@ public class StrictHttpFirewallTests {
@@ -121,11 +114,8 @@ public class StrictHttpFirewallTests {
for ( String path : this . unnormalizedPaths ) {
this . request = new MockHttpServletRequest ( "GET" , "" ) ;
this . request . setServletPath ( path ) ;
try {
this . firewall . getFirewalledRequest ( this . request ) ;
fail ( path + " is un-normalized" ) ;
} catch ( RequestRejectedException expected ) {
}
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
}
@ -134,105 +124,99 @@ public class StrictHttpFirewallTests {
@@ -134,105 +124,99 @@ public class StrictHttpFirewallTests {
for ( String path : this . unnormalizedPaths ) {
this . request = new MockHttpServletRequest ( "GET" , "" ) ;
this . request . setPathInfo ( path ) ;
try {
this . firewall . getFirewalledRequest ( this . request ) ;
fail ( path + " is un-normalized" ) ;
} catch ( RequestRejectedException expected ) {
}
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
}
// --- ; ---
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenSemicolonInContextPathThenThrowsRequestRejectedException ( ) {
this . request . setContextPath ( ";/context" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenSemicolonInServletPathThenThrowsRequestRejectedException ( ) {
this . request . setServletPath ( "/spring;/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenSemicolonInPathInfoThenThrowsRequestRejectedException ( ) {
this . request . setPathInfo ( "/path;/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenSemicolonInRequestUriThenThrowsRequestRejectedException ( ) {
this . request . setRequestURI ( "/path;/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenEncodedSemicolonInContextPathThenThrowsRequestRejectedException ( ) {
this . request . setContextPath ( "%3B/context" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenEncodedSemicolonInServletPathThenThrowsRequestRejectedException ( ) {
this . request . setServletPath ( "/spring%3B/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenEncodedSemicolonInPathInfoThenThrowsRequestRejectedException ( ) {
this . request . setPathInfo ( "/path%3B/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenEncodedSemicolonInRequestUriThenThrowsRequestRejectedException ( ) {
this . request . setRequestURI ( "/path%3B/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenLowercaseEncodedSemicolonInContextPathThenThrowsRequestRejectedException ( ) {
this . request . setContextPath ( "%3b/context" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenLowercaseEncodedSemicolonInServletPathThenThrowsRequestRejectedException ( ) {
this . request . setServletPath ( "/spring%3b/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenLowercaseEncodedSemicolonInPathInfoThenThrowsRequestRejectedException ( ) {
this . request . setPathInfo ( "/path%3b/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenLowercaseEncodedSemicolonInRequestUriThenThrowsRequestRejectedException ( ) {
this . request . setRequestURI ( "/path%3b/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenSemicolonInContextPathAndAllowSemicolonThenNoException ( ) {
this . firewall . setAllowSemicolon ( true ) ;
this . request . setContextPath ( ";/context" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -240,7 +224,6 @@ public class StrictHttpFirewallTests {
@@ -240,7 +224,6 @@ public class StrictHttpFirewallTests {
public void getFirewalledRequestWhenSemicolonInServletPathAndAllowSemicolonThenNoException ( ) {
this . firewall . setAllowSemicolon ( true ) ;
this . request . setServletPath ( "/spring;/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -248,7 +231,6 @@ public class StrictHttpFirewallTests {
@@ -248,7 +231,6 @@ public class StrictHttpFirewallTests {
public void getFirewalledRequestWhenSemicolonInPathInfoAndAllowSemicolonThenNoException ( ) {
this . firewall . setAllowSemicolon ( true ) ;
this . request . setPathInfo ( "/path;/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -256,7 +238,6 @@ public class StrictHttpFirewallTests {
@@ -256,7 +238,6 @@ public class StrictHttpFirewallTests {
public void getFirewalledRequestWhenSemicolonInRequestUriAndAllowSemicolonThenNoException ( ) {
this . firewall . setAllowSemicolon ( true ) ;
this . request . setRequestURI ( "/path;/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -265,7 +246,6 @@ public class StrictHttpFirewallTests {
@@ -265,7 +246,6 @@ public class StrictHttpFirewallTests {
this . firewall . setAllowUrlEncodedPercent ( true ) ;
this . firewall . setAllowSemicolon ( true ) ;
this . request . setContextPath ( "%3B/context" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -274,7 +254,6 @@ public class StrictHttpFirewallTests {
@@ -274,7 +254,6 @@ public class StrictHttpFirewallTests {
this . firewall . setAllowUrlEncodedPercent ( true ) ;
this . firewall . setAllowSemicolon ( true ) ;
this . request . setServletPath ( "/spring%3B/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -283,7 +262,6 @@ public class StrictHttpFirewallTests {
@@ -283,7 +262,6 @@ public class StrictHttpFirewallTests {
this . firewall . setAllowUrlEncodedPercent ( true ) ;
this . firewall . setAllowSemicolon ( true ) ;
this . request . setPathInfo ( "/path%3B/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -291,7 +269,6 @@ public class StrictHttpFirewallTests {
@@ -291,7 +269,6 @@ public class StrictHttpFirewallTests {
public void getFirewalledRequestWhenEncodedSemicolonInRequestUriAndAllowSemicolonThenNoException ( ) {
this . firewall . setAllowSemicolon ( true ) ;
this . request . setRequestURI ( "/path%3B/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -300,7 +277,6 @@ public class StrictHttpFirewallTests {
@@ -300,7 +277,6 @@ public class StrictHttpFirewallTests {
this . firewall . setAllowUrlEncodedPercent ( true ) ;
this . firewall . setAllowSemicolon ( true ) ;
this . request . setContextPath ( "%3b/context" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -309,7 +285,6 @@ public class StrictHttpFirewallTests {
@@ -309,7 +285,6 @@ public class StrictHttpFirewallTests {
this . firewall . setAllowUrlEncodedPercent ( true ) ;
this . firewall . setAllowSemicolon ( true ) ;
this . request . setServletPath ( "/spring%3b/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -318,7 +293,6 @@ public class StrictHttpFirewallTests {
@@ -318,7 +293,6 @@ public class StrictHttpFirewallTests {
this . firewall . setAllowUrlEncodedPercent ( true ) ;
this . firewall . setAllowSemicolon ( true ) ;
this . request . setPathInfo ( "/path%3b/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@ -326,38 +300,35 @@ public class StrictHttpFirewallTests {
@@ -326,38 +300,35 @@ public class StrictHttpFirewallTests {
public void getFirewalledRequestWhenLowercaseEncodedSemicolonInRequestUriAndAllowSemicolonThenNoException ( ) {
this . firewall . setAllowSemicolon ( true ) ;
this . request . setRequestURI ( "/path%3b/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
// --- encoded . ---
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenEncodedPeriodInThenThrowsRequestRejectedException ( ) {
this . request . setRequestURI ( "/%2E/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenLowercaseEncodedPeriodInThenThrowsRequestRejectedException ( ) {
this . request . setRequestURI ( "/%2e/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenAllowEncodedPeriodAndEncodedPeriodInThenNoException ( ) {
this . firewall . setAllowUrlEncodedPeriod ( true ) ;
this . request . setRequestURI ( "/%2E/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenExceedsLowerboundAsciiThenException ( ) {
this . request . setRequestURI ( "/\u0019" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
@ -372,13 +343,46 @@ public class StrictHttpFirewallTests {
@@ -372,13 +343,46 @@ public class StrictHttpFirewallTests {
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenJapaneseCharacterThenNoException ( ) {
this . request . setServletPath ( "/\u3042" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test
public void getFirewalledRequestWhenExceedsUpperboundAsciiThenException ( ) {
this . request . setRequestURI ( "/\u007f" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
// --- from DefaultHttpFirewallTests ---
@Test
public void getFirewalledRequestWhenContainsNullThenException ( ) {
this . request . setRequestURI ( "/\0" ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenContainsEncodedNullThenException ( ) {
this . request . setRequestURI ( "/something%00/" ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenContainsLowercaseEncodedLineFeedThenException ( ) {
this . request . setRequestURI ( "/something%0a/" ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenContainsUppercaseEncodedLineFeedThenException ( ) {
this . request . setRequestURI ( "/something%0A/" ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenContainsLineFeedThenException ( ) {
@ -394,6 +398,20 @@ public class StrictHttpFirewallTests {
@@ -394,6 +398,20 @@ public class StrictHttpFirewallTests {
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenContainsLowercaseEncodedCarriageReturnThenException ( ) {
this . request . setRequestURI ( "/something%0d/" ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenContainsUppercaseEncodedCarriageReturnThenException ( ) {
this . request . setRequestURI ( "/something%0D/" ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenContainsCarriageReturnThenException ( ) {
this . request . setRequestURI ( "/something\r/" ) ;
@ -408,29 +426,119 @@ public class StrictHttpFirewallTests {
@@ -408,29 +426,119 @@ public class StrictHttpFirewallTests {
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenServletPathContainsLineSeparatorThenException ( ) {
this . request . setServletPath ( "/something\u2028/" ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenServletPathContainsParagraphSeparatorThenException ( ) {
this . request . setServletPath ( "/something\u2029/" ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenContainsLowercaseEncodedLineFeedAndAllowedThenNoException ( ) {
this . firewall . setAllowUrlEncodedLineFeed ( true ) ;
this . request . setRequestURI ( "/something%0a/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test
public void getFirewalledRequestWhenContainsUppercaseEncodedLineFeedAndAllowedThenNoException ( ) {
this . firewall . setAllowUrlEncodedLineFeed ( true ) ;
this . request . setRequestURI ( "/something%0A/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test
public void getFirewalledRequestWhenContainsLineFeedAndAllowedThenException ( ) {
this . firewall . setAllowUrlEncodedLineFeed ( true ) ;
this . request . setRequestURI ( "/something\n/" ) ;
// Expected an error because the line feed is decoded in an encoded part of the
// URL
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenServletPathContainsLineFeedAndAllowedThenNoException ( ) {
this . firewall . setAllowUrlEncodedLineFeed ( true ) ;
this . request . setServletPath ( "/something\n/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test
public void getFirewalledRequestWhenContainsLowercaseEncodedCarriageReturnAndAllowedThenNoException ( ) {
this . firewall . setAllowUrlEncodedCarriageReturn ( true ) ;
this . request . setRequestURI ( "/something%0d/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test
public void getFirewalledRequestWhenContainsUppercaseEncodedCarriageReturnAndAllowedThenNoException ( ) {
this . firewall . setAllowUrlEncodedCarriageReturn ( true ) ;
this . request . setRequestURI ( "/something%0D/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test
public void getFirewalledRequestWhenContainsCarriageReturnAndAllowedThenNoException ( ) {
this . firewall . setAllowUrlEncodedCarriageReturn ( true ) ;
this . request . setRequestURI ( "/something\r/" ) ;
// Expected an error because the carriage return is decoded in an encoded part of
// the URL
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
public void getFirewalledRequestWhenServletPathContainsCarriageReturnAndAllowedThenNoException ( ) {
this . firewall . setAllowUrlEncodedCarriageReturn ( true ) ;
this . request . setServletPath ( "/something\r/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test
public void getFirewalledRequestWhenServletPathContainsLineSeparatorAndAllowedThenNoException ( ) {
this . firewall . setAllowUrlEncodedLineSeparator ( true ) ;
this . request . setServletPath ( "/something\u2028/" ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test
public void getFirewalledRequestWhenServletPathContainsParagraphSeparatorAndAllowedThenNoException ( ) {
this . firewall . setAllowUrlEncodedParagraphSeparator ( true ) ;
this . request . setServletPath ( "/something\u2029/" ) ;
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 will strip the ; content from requestURI before the path
* is URL decoded .
* 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
* will strip the ; content from requestURI before the path is URL decoded .
* /
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenLowercaseEncodedPathThenException ( ) {
this . request . setRequestURI ( "/context-root/a/b;%2f1/c" ) ;
this . request . setContextPath ( "/context-root" ) ;
this . request . setServletPath ( "" ) ;
this . request . setPathInfo ( "/a/b;/1/c" ) ; // URL decoded requestURI
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenUppercaseEncodedPathThenException ( ) {
this . request . setRequestURI ( "/context-root/a/b;%2F1/c" ) ;
this . request . setContextPath ( "/context-root" ) ;
this . request . setServletPath ( "" ) ;
this . request . setPathInfo ( "/a/b;/1/c" ) ; // URL decoded requestURI
this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
@Test
@ -442,7 +550,6 @@ public class StrictHttpFirewallTests {
@@ -442,7 +550,6 @@ public class StrictHttpFirewallTests {
request . setContextPath ( "/context-root" ) ;
request . setServletPath ( "" ) ;
request . setPathInfo ( "/a/b;/1/c" ) ; // URL decoded requestURI
this . firewall . getFirewalledRequest ( request ) ;
}
@ -455,7 +562,6 @@ public class StrictHttpFirewallTests {
@@ -455,7 +562,6 @@ public class StrictHttpFirewallTests {
request . setContextPath ( "/context-root" ) ;
request . setServletPath ( "" ) ;
request . setPathInfo ( "/a/b;/1/c" ) ; // URL decoded requestURI
this . firewall . getFirewalledRequest ( request ) ;
}
@ -468,7 +574,7 @@ public class StrictHttpFirewallTests {
@@ -468,7 +574,7 @@ public class StrictHttpFirewallTests {
request . setContextPath ( "/context-root" ) ;
request . setServletPath ( "" ) ;
request . setPathInfo ( "/a/b//c" ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
@ -480,7 +586,7 @@ public class StrictHttpFirewallTests {
@@ -480,7 +586,7 @@ public class StrictHttpFirewallTests {
request . setContextPath ( "/context-root" ) ;
request . setServletPath ( "" ) ;
request . setPathInfo ( "/a/b//c" ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
@ -492,7 +598,7 @@ public class StrictHttpFirewallTests {
@@ -492,7 +598,7 @@ public class StrictHttpFirewallTests {
request . setContextPath ( "/context-root" ) ;
request . setServletPath ( "" ) ;
request . setPathInfo ( "/a/b//c" ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
@ -504,7 +610,7 @@ public class StrictHttpFirewallTests {
@@ -504,7 +610,7 @@ public class StrictHttpFirewallTests {
request . setContextPath ( "/context-root" ) ;
request . setServletPath ( "" ) ;
request . setPathInfo ( "/a/b//c" ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
@ -513,7 +619,7 @@ public class StrictHttpFirewallTests {
@@ -513,7 +619,7 @@ public class StrictHttpFirewallTests {
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setRequestURI ( "/context-root/a/b%2F%2Fc" ) ;
this . firewall . getEncodedUrlBlacklist ( ) . removeAll ( Arrays . asList ( "%2F%2F" ) ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
@ -522,7 +628,7 @@ public class StrictHttpFirewallTests {
@@ -522,7 +628,7 @@ public class StrictHttpFirewallTests {
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setRequestURI ( "/context-root/a/b%2f%2fc" ) ;
this . firewall . getEncodedUrlBlacklist ( ) . removeAll ( Arrays . asList ( "%2f%2f" ) ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
@ -531,7 +637,7 @@ public class StrictHttpFirewallTests {
@@ -531,7 +637,7 @@ public class StrictHttpFirewallTests {
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setRequestURI ( "/context-root/a/b%2f%2Fc" ) ;
this . firewall . getEncodedUrlBlacklist ( ) . removeAll ( Arrays . asList ( "%2f%2F" ) ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
@ -540,7 +646,7 @@ public class StrictHttpFirewallTests {
@@ -540,7 +646,7 @@ public class StrictHttpFirewallTests {
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setRequestURI ( "/context-root/a/b%2F%2fc" ) ;
this . firewall . getEncodedUrlBlacklist ( ) . removeAll ( Arrays . asList ( "%2F%2f" ) ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
@ -548,22 +654,234 @@ public class StrictHttpFirewallTests {
@@ -548,22 +654,234 @@ public class StrictHttpFirewallTests {
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setPathInfo ( "/a/b//c" ) ;
this . firewall . getDecodedUrlBlacklist ( ) . removeAll ( Arrays . asList ( "//" ) ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
// blocklist
@Test
public void getFirewalledRequestWhenRemoveFromUpperCaseEncodedUrlBlocklistThenNoException ( ) {
this . firewall . setAllowUrlEncodedSlash ( true ) ;
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setRequestURI ( "/context-root/a/b%2F%2Fc" ) ;
this . firewall . getEncodedUrlBlocklist ( ) . removeAll ( Arrays . asList ( "%2F%2F" ) ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
public void getFirewalledRequestWhenRemoveFromLowerCaseEncodedUrlBlocklistThenNoException ( ) {
this . firewall . setAllowUrlEncodedSlash ( true ) ;
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setRequestURI ( "/context-root/a/b%2f%2fc" ) ;
this . firewall . getEncodedUrlBlocklist ( ) . removeAll ( Arrays . asList ( "%2f%2f" ) ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
public void getFirewalledRequestWhenRemoveFromLowerCaseAndUpperCaseEncodedUrlBlocklistThenNoException ( ) {
this . firewall . setAllowUrlEncodedSlash ( true ) ;
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setRequestURI ( "/context-root/a/b%2f%2Fc" ) ;
this . firewall . getEncodedUrlBlocklist ( ) . removeAll ( Arrays . asList ( "%2f%2F" ) ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
public void getFirewalledRequestWhenRemoveFromUpperCaseAndLowerCaseEncodedUrlBlocklistThenNoException ( ) {
this . firewall . setAllowUrlEncodedSlash ( true ) ;
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setRequestURI ( "/context-root/a/b%2F%2fc" ) ;
this . firewall . getEncodedUrlBlocklist ( ) . removeAll ( Arrays . asList ( "%2F%2f" ) ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
public void getFirewalledRequestWhenRemoveFromDecodedUrlBlocklistThenNoException ( ) {
MockHttpServletRequest request = new MockHttpServletRequest ( "GET" , "" ) ;
request . setPathInfo ( "/a/b//c" ) ;
this . firewall . getDecodedUrlBlocklist ( ) . removeAll ( Arrays . asList ( "//" ) ) ;
this . firewall . getFirewalledRequest ( request ) ;
}
@Test
public void getFirewalledRequestWhenTrustedDomainThenNoException ( ) {
this . request . addHeader ( "Host" , "example.org" ) ;
this . firewall . setAllowedHostnames ( hostname - > hostname . equals ( "example.org" ) ) ;
assertThatCode ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) . doesNotThrowAnyException ( ) ;
this . firewall . setAllowedHostnames ( ( hostname ) - > hostname . equals ( "example.org" ) ) ;
this . firewall . getFirewalledRequest ( this . request ) ;
}
@Test ( expected = RequestRejectedException . class )
@Test
public void getFirewalledRequestWhenUntrustedDomainThenException ( ) {
this . request . addHeader ( "Host" , "example.org" ) ;
this . firewall . setAllowedHostnames ( hostname - > hostname . equals ( "myexample.org" ) ) ;
this . firewall . setAllowedHostnames ( ( hostname ) - > hostname . equals ( "myexample.org" ) ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > this . firewall . getFirewalledRequest ( this . request ) ) ;
}
this . firewall . getFirewalledRequest ( this . request ) ;
@Test
public void getFirewalledRequestGetHeaderWhenNotAllowedHeaderNameThenException ( ) {
this . firewall . setAllowedHeaderNames ( ( 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" ) ;
this . firewall . setAllowedHeaderValues ( ( 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" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( ( ) - > request . getDateHeader ( "Bad\0Name" ) ) ;
}
@Test
public void getFirewalledRequestGetIntHeaderWhenControlCharacterInHeaderNameThenException ( ) {
this . request . addHeader ( "Bad\0Name" , "some value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( ( ) - > request . getIntHeader ( "Bad\0Name" ) ) ;
}
@Test
public void getFirewalledRequestGetHeaderWhenControlCharacterInHeaderNameThenException ( ) {
this . request . addHeader ( "Bad\0Name" , "some value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( ( ) - > request . getHeader ( "Bad\0Name" ) ) ;
}
@Test
public void getFirewalledRequestGetHeaderWhenUndefinedCharacterInHeaderNameThenException ( ) {
this . request . addHeader ( "Bad\uFFFEName" , "some value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( ( ) - > request . getHeader ( "Bad\uFFFEName" ) ) ;
}
@Test
public void getFirewalledRequestGetHeadersWhenControlCharacterInHeaderNameThenException ( ) {
this . request . addHeader ( "Bad\0Name" , "some value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( ( ) - > request . getHeaders ( "Bad\0Name" ) ) ;
}
@Test
public void getFirewalledRequestGetHeaderNamesWhenControlCharacterInHeaderNameThenException ( ) {
this . request . addHeader ( "Bad\0Name" , "some value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > request . getHeaderNames ( ) . nextElement ( ) ) ;
}
@Test
public void getFirewalledRequestGetHeaderWhenControlCharacterInHeaderValueThenException ( ) {
this . request . addHeader ( "Something" , "bad\0value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( ( ) - > request . getHeader ( "Something" ) ) ;
}
@Test
public void getFirewalledRequestGetHeaderWhenUndefinedCharacterInHeaderValueThenException ( ) {
this . request . addHeader ( "Something" , "bad\uFFFEvalue" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( ( ) - > request . getHeader ( "Something" ) ) ;
}
@Test
public void getFirewalledRequestGetHeadersWhenControlCharacterInHeaderValueThenException ( ) {
this . request . addHeader ( "Something" , "bad\0value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > request . getHeaders ( "Something" ) . nextElement ( ) ) ;
}
@Test
public void getFirewalledRequestGetParameterWhenControlCharacterInParameterNameThenException ( ) {
this . request . addParameter ( "Bad\0Name" , "some value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( ( ) - > request . getParameter ( "Bad\0Name" ) ) ;
}
@Test
public void getFirewalledRequestGetParameterMapWhenControlCharacterInParameterNameThenException ( ) {
this . request . addParameter ( "Bad\0Name" , "some value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( request : : getParameterMap ) ;
}
@Test
public void getFirewalledRequestGetParameterNamesWhenControlCharacterInParameterNameThenException ( ) {
this . request . addParameter ( "Bad\0Name" , "some value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( request . getParameterNames ( ) : : nextElement ) ;
}
@Test
public void getFirewalledRequestGetParameterNamesWhenUndefinedCharacterInParameterNameThenException ( ) {
this . request . addParameter ( "Bad\uFFFEName" , "some value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class ) . isThrownBy ( request . getParameterNames ( ) : : nextElement ) ;
}
@Test
public void getFirewalledRequestGetParameterValuesWhenNotAllowedInParameterValueThenException ( ) {
this . firewall . setAllowedParameterValues ( ( value ) - > ! value . equals ( "bad value" ) ) ;
this . request . addParameter ( "Something" , "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" ) ) ;
this . request . addParameter ( "bad name" , "good value" ) ;
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( RequestRejectedException . class )
. isThrownBy ( ( ) - > request . getParameterValues ( "bad name" ) ) ;
}
// gh-9598
@Test
public void getFirewalledRequestGetParameterWhenNameIsNullThenIllegalArgumentException ( ) {
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( IllegalArgumentException . class ) . isThrownBy ( ( ) - > request . getParameter ( null ) ) ;
}
// gh-9598
@Test
public void getFirewalledRequestGetParameterValuesWhenNameIsNullThenIllegalArgumentException ( ) {
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThatExceptionOfType ( IllegalArgumentException . class ) . isThrownBy ( ( ) - > request . getParameterValues ( null ) ) ;
}
// gh-9598
@Test
public void getFirewalledRequestGetHeaderWhenNameIsNullThenNull ( ) {
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThat ( request . getHeader ( null ) ) . isNull ( ) ;
}
// gh-9598
@Test
public void getFirewalledRequestGetHeadersWhenNameIsNullThenEmptyEnumeration ( ) {
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThat ( request . getHeaders ( null ) . hasMoreElements ( ) ) . isFalse ( ) ;
}
// gh-9598
@Test
public void getFirewalledRequestGetIntHeaderWhenNameIsNullThenNegativeOne ( ) {
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThat ( request . getIntHeader ( null ) ) . isEqualTo ( - 1 ) ;
}
@Test
public void getFirewalledRequestGetDateHeaderWhenNameIsNullThenNegativeOne ( ) {
HttpServletRequest request = this . firewall . getFirewalledRequest ( this . request ) ;
assertThat ( request . getDateHeader ( null ) ) . isEqualTo ( - 1 ) ;
}
}