Skip to content

Commit a6d1947

Browse files
committed
Add Header and Parameter Value Documentation
Closes gh-9038
1 parent 7ef3f61 commit a6d1947

File tree

1 file changed

+101
-0
lines changed
  • docs/manual/src/docs/asciidoc/_includes/servlet/exploits

1 file changed

+101
-0
lines changed

docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc

+101
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,104 @@ See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue requesting t
131131

132132
If you must allow any HTTP method (not recommended), you can use `StrictHttpFirewall.setUnsafeAllowAnyHttpMethod(true)`.
133133
This will disable validation of the HTTP method entirely.
134+
135+
`StrictHttpFirewall` also checks header names and values and parameter names.
136+
It requires that each character have a defined code point and not be a control character.
137+
138+
This requirement can be relaxed or adjusted as necessary using the following methods:
139+
140+
* `StrictHttpFirewall#setAllowedHeaderNames(Predicate)`
141+
* `StrictHttpFirewall#setAllowedHeaderValues(Predicate)`
142+
* `StrictHttpFirewall#setAllowedParameterNames(Predicate)`
143+
144+
NOTE: Also, parameter values can be controlled with `setAllowedParameterValues(Predicate)`.
145+
146+
For example, to switch off this check, you can wire your `StrictHttpFirewall` with `Predicate` s that always return `true`, like so:
147+
148+
.Allow Any Header Name, Header Value, and Parameter Name
149+
====
150+
.Java
151+
[source,java,role="primary"]
152+
----
153+
@Bean
154+
public StrictHttpFirewall httpFirewall() {
155+
StrictHttpFirewall firewall = new StrictHttpFirewall();
156+
firewall.setAllowedHeaderNames((header) -> true);
157+
firewall.setAllowedHeaderValues((header) -> true);
158+
firewall.setAllowedParameterNames((parameter) -> true);
159+
return firewall;
160+
}
161+
----
162+
163+
.Kotlin
164+
[source,kotlin,role="secondary"]
165+
----
166+
@Bean
167+
fun httpFirewall(): StrictHttpFirewall {
168+
val firewall = StrictHttpFirewall()
169+
firewall.setAllowedHeaderNames { true }
170+
firewall.setAllowedHeaderValues { true }
171+
firewall.setAllowedParameterNames { true }
172+
return firewall
173+
}
174+
----
175+
====
176+
177+
Or, there might be a specific value that you need to allow.
178+
179+
For example, iPhone Xʀ uses a `User-Agent` that includes a character not in the ISO-8859-1 charset.
180+
Due to this fact, some application servers will parse this value into two separate characters, the latter being an undefined character.
181+
182+
You can address this with the `setAllowedHeaderValues` method, as you can see below:
183+
184+
.Allow Certain User Agents
185+
====
186+
.Java
187+
[source,java,role="primary"]
188+
----
189+
@Bean
190+
public StrictHttpFirewall httpFirewall() {
191+
StrictHttpFirewall firewall = new StrictHttpFirewall();
192+
Pattern allowed = Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]]*");
193+
Pattern userAgent = ...;
194+
firewall.setAllowedHeaderValues((header) -> allowed.matcher(header).matches() || userAgent.matcher(header).matches());
195+
return firewall;
196+
}
197+
----
198+
199+
.Kotlin
200+
[source,kotlin,role="secondary"]
201+
----
202+
@Bean
203+
fun httpFirewall(): StrictHttpFirewall {
204+
val firewall = StrictHttpFirewall()
205+
val allowed = Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]]*")
206+
val userAgent = Pattern.compile(...)
207+
firewall.setAllowedHeaderValues { allowed.matcher(it).matches() || userAgent.matcher(it).matches() }
208+
return firewall
209+
}
210+
----
211+
====
212+
213+
In the case of header values, you may instead consider parsing them as UTF-8 at verification time like so:
214+
215+
.Parse Headers As UTF-8
216+
====
217+
.Java
218+
[source,java,role="primary"]
219+
----
220+
firewall.setAllowedHeaderValues((header) -> {
221+
String parsed = new String(header.getBytes(ISO_8859_1), UTF_8);
222+
return allowed.matcher(parsed).matches();
223+
});
224+
----
225+
226+
.Kotlin
227+
[source,kotlin,role="secondary"]
228+
----
229+
firewall.setAllowedHeaderValues {
230+
val parsed = String(header.getBytes(ISO_8859_1), UTF_8)
231+
return allowed.matcher(parsed).matches()
232+
}
233+
----
234+
====

0 commit comments

Comments
 (0)