Skip to content

Commit

Permalink
Add Header and Parameter Value Documentation
Browse files Browse the repository at this point in the history
Closes gh-9038
  • Loading branch information
jzheaux committed Oct 1, 2020
1 parent 7ef3f61 commit a6d1947
Showing 1 changed file with 101 additions and 0 deletions.
101 changes: 101 additions & 0 deletions docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,104 @@ See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue requesting t

If you must allow any HTTP method (not recommended), you can use `StrictHttpFirewall.setUnsafeAllowAnyHttpMethod(true)`.
This will disable validation of the HTTP method entirely.

`StrictHttpFirewall` 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 using the following methods:

* `StrictHttpFirewall#setAllowedHeaderNames(Predicate)`
* `StrictHttpFirewall#setAllowedHeaderValues(Predicate)`
* `StrictHttpFirewall#setAllowedParameterNames(Predicate)`

NOTE: Also, parameter values can be controlled with `setAllowedParameterValues(Predicate)`.

For example, to switch off this check, you can wire your `StrictHttpFirewall` with `Predicate` s that always return `true`, like so:

.Allow Any Header Name, Header Value, and Parameter Name
====
.Java
[source,java,role="primary"]
----
@Bean
public StrictHttpFirewall httpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowedHeaderNames((header) -> true);
firewall.setAllowedHeaderValues((header) -> true);
firewall.setAllowedParameterNames((parameter) -> true);
return firewall;
}
----
.Kotlin
[source,kotlin,role="secondary"]
----
@Bean
fun httpFirewall(): StrictHttpFirewall {
val firewall = StrictHttpFirewall()
firewall.setAllowedHeaderNames { true }
firewall.setAllowedHeaderValues { true }
firewall.setAllowedParameterNames { true }
return firewall
}
----
====

Or, there might be a specific value that you need to allow.

For example, iPhone Xʀ uses a `User-Agent` that includes a character not in the ISO-8859-1 charset.
Due to this fact, some application servers will parse this value into two separate characters, the latter being an undefined character.

You can address this with the `setAllowedHeaderValues` method, as you can see below:

.Allow Certain User Agents
====
.Java
[source,java,role="primary"]
----
@Bean
public StrictHttpFirewall httpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
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(): StrictHttpFirewall {
val firewall = StrictHttpFirewall()
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 like so:

.Parse Headers As UTF-8
====
.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()
}
----
====

0 comments on commit a6d1947

Please sign in to comment.