| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 | 
							- [[webflux-serverwebexchangefirewall]]
 
- = ServerWebExchangeFirewall
 
- There are various ways a request can be created by malicious users that can exploit applications.
 
- Spring Security provides the `ServerWebExchangeFirewall` to allow rejecting requests that look malicious.
 
- The default implementation is `StrictServerWebExchangeFirewall` which rejects malicious requests.
 
- For example a request could contain path-traversal sequences (such as `/../`) or multiple forward slashes (`//`) that could also cause pattern-matches to fail.
 
- Some containers normalize these out before performing the servlet mapping, but others do not.
 
- To protect against issues like these, `WebFilterChainProxy` uses a `ServerWebExchangeFirewall` strategy to check and wrap the request.
 
- By default, un-normalized requests are automatically rejected, and path parameters are removed for matching purposes.
 
- (So, for example, an original request path of `/secure;hack=1/somefile.html;hack=2` is returned as `/secure/somefile.html`.)
 
- It is, therefore, essential that a `WebFilterChainProxy` is used.
 
- In practice, we recommend that you use method security at your service layer, to control access to your application, rather than rely entirely on the use of security constraints defined at the web-application level.
 
- URLs change, and it is difficult to take into account all the possible URLs that an application might support and how requests might be manipulated.
 
- You should restrict yourself to using a few simple patterns that are simple to understand.
 
- Always try to use a "`deny-by-default`" approach, where you have a catch-all wildcard (`/**` or `**`) defined last to deny access.
 
- Security defined at the service layer is much more robust and harder to bypass, so you should always take advantage of Spring Security's method security options.
 
- You can customize the `ServerWebExchangeFirewall` by exposing it as a Bean.
 
- .Allow Matrix Variables
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- public StrictServerWebExchangeFirewall httpFirewall() {
 
-     StrictServerWebExchangeFirewall firewall = new StrictServerWebExchangeFirewall();
 
-     firewall.setAllowSemicolon(true);
 
-     return firewall;
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- fun httpFirewall(): StrictServerWebExchangeFirewall {
 
-     val firewall = StrictServerWebExchangeFirewall()
 
-     firewall.setAllowSemicolon(true)
 
-     return firewall
 
- }
 
- ----
 
- ======
 
- To protect against https://www.owasp.org/index.php/Cross_Site_Tracing[Cross Site Tracing (XST)] and https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)[HTTP Verb Tampering], the `StrictServerWebExchangeFirewall` provides an allowed list of valid HTTP methods that are allowed.
 
- The default valid methods are `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, and `PUT`.
 
- If your application needs to modify the valid methods, you can configure a custom `StrictServerWebExchangeFirewall` bean.
 
- The following example allows only HTTP `GET` and `POST` methods:
 
- .Allow Only GET & POST
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- public StrictServerWebExchangeFirewall httpFirewall() {
 
-     StrictServerWebExchangeFirewall firewall = new StrictServerWebExchangeFirewall();
 
-     firewall.setAllowedHttpMethods(Arrays.asList("GET", "POST"));
 
-     return firewall;
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- fun httpFirewall(): StrictServerWebExchangeFirewall {
 
-     val firewall = StrictServerWebExchangeFirewall()
 
-     firewall.setAllowedHttpMethods(listOf("GET", "POST"))
 
-     return firewall
 
- }
 
- ----
 
- ======
 
- If you must allow any HTTP method (not recommended), you can use `StrictServerWebExchangeFirewall.setUnsafeAllowAnyHttpMethod(true)`.
 
- Doing so entirely disables validation of the HTTP method.
 
- [[webflux-serverwebexchangefirewall-headers-parameters]]
 
- `StrictServerWebExchangeFirewall` also checks header names and values and parameter names.
 
- It requires that each character have a defined code point and not be a control character.
 
- This requirement can be relaxed or adjusted as necessary by using the following methods:
 
- * `StrictServerWebExchangeFirewall#setAllowedHeaderNames(Predicate)`
 
- * `StrictServerWebExchangeFirewall#setAllowedHeaderValues(Predicate)`
 
- * `StrictServerWebExchangeFirewall#setAllowedParameterNames(Predicate)`
 
- [NOTE]
 
- ====
 
- Parameter values can be also controlled with `setAllowedParameterValues(Predicate)`.
 
- ====
 
- For example, to switch off this check, you can wire your `StrictServerWebExchangeFirewall` with `Predicate` instances that always return `true`:
 
- .Allow Any Header Name, Header Value, and Parameter Name
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- public StrictServerWebExchangeFirewall httpFirewall() {
 
-     StrictServerWebExchangeFirewall firewall = new StrictServerWebExchangeFirewall();
 
-     firewall.setAllowedHeaderNames((header) -> true);
 
-     firewall.setAllowedHeaderValues((header) -> true);
 
-     firewall.setAllowedParameterNames((parameter) -> true);
 
-     return firewall;
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- fun httpFirewall(): StrictServerWebExchangeFirewall {
 
-     val firewall = StrictServerWebExchangeFirewall()
 
-     firewall.setAllowedHeaderNames { true }
 
-     firewall.setAllowedHeaderValues { true }
 
-     firewall.setAllowedParameterNames { true }
 
-     return firewall
 
- }
 
- ----
 
- ======
 
- Alternatively, there might be a specific value that you need to allow.
 
- For example, iPhone Xʀ uses a `User-Agent` that includes a character that is not in the ISO-8859-1 charset.
 
- Due to this fact, some application servers parse this value into two separate characters, the latter being an undefined character.
 
- You can address this with the `setAllowedHeaderValues` method:
 
- .Allow Certain User Agents
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- public StrictServerWebExchangeFirewall httpFirewall() {
 
-     StrictServerWebExchangeFirewall firewall = new StrictServerWebExchangeFirewall();
 
-     Pattern allowed = Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]]*");
 
-     Pattern userAgent = ...;
 
-     firewall.setAllowedHeaderValues((header) -> allowed.matcher(header).matches() || userAgent.matcher(header).matches());
 
-     return firewall;
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- fun httpFirewall(): StrictServerWebExchangeFirewall {
 
-     val firewall = StrictServerWebExchangeFirewall()
 
-     val allowed = Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]]*")
 
-     val userAgent = Pattern.compile(...)
 
-     firewall.setAllowedHeaderValues { allowed.matcher(it).matches() || userAgent.matcher(it).matches() }
 
-     return firewall
 
- }
 
- ----
 
- ======
 
- In the case of header values, you may instead consider parsing them as UTF-8 at verification time:
 
- .Parse Headers As UTF-8
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- firewall.setAllowedHeaderValues((header) -> {
 
-     String parsed = new String(header.getBytes(ISO_8859_1), UTF_8);
 
-     return allowed.matcher(parsed).matches();
 
- });
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- firewall.setAllowedHeaderValues {
 
-     val parsed = String(header.getBytes(ISO_8859_1), UTF_8)
 
-     return allowed.matcher(parsed).matches()
 
- }
 
- ----
 
- ======
 
- The `ServerExchangeRejectedHandler` interface is used to handle `ServerExchangeRejectedException` throw by Spring Security's `ServerWebExchangeFirewall`.
 
- By default `HttpStatusExchangeRejectedHandler` is used to send an HTTP 400 response to clients when a request is rejected.
 
- To customize the behavior, users can expose a `ServerExchangeRejectedHandler` Bean.
 
- For example, the following will send an HTTP 404 when the request is rejected:
 
- .Send 404 on Request Rejected
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- ServerExchangeRejectedHandler rejectedHandler() {
 
- 	return new HttpStatusExchangeRejectedHandler(HttpStatus.NOT_FOUND);
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- fun rejectedHandler(): ServerExchangeRejectedHandler {
 
-     return HttpStatusExchangeRejectedHandler(HttpStatus.NOT_FOUND)
 
- }
 
- ----
 
- ======
 
- Handling can be completely customized by creating a custom `ServerExchangeRejectedHandler` implementation.
 
 
  |