mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
69 lines
3.3 KiB
Plaintext
69 lines
3.3 KiB
Plaintext
Data binding involves binding untrusted input onto application objects.
|
|
For security reasons, it's crucial to ensure that input is properly constrained to expected fields only.
|
|
This section provides guidance for safe binding.
|
|
|
|
First, prefer **immutable object design** for web binding purposes.
|
|
It is safe because a constructor naturally constrains binding to expected inputs.
|
|
You can use a Java record or a class with a primary constructor, and either can have further nested objects.
|
|
See xref:core/validation/data-binding.adoc#data-binding-constructor-binding[Constructor Binding] for details.
|
|
|
|
Another option for safe binding is to use **dedicated objects** designed for the expected input.
|
|
Such objects, even if mutable, are safe because they constrain binding to the expected inputs.
|
|
|
|
Domain objects such as JPA or Hibernate entities are generally not safe for web binding
|
|
as they likely contain more properties than the expected inputs.
|
|
For such cases, it's crucial to declare the properties to expose for binding.
|
|
For example:
|
|
|
|
[source,java,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
@Controller
|
|
public class PersonController {
|
|
|
|
@InitBinder
|
|
void initBinder(WebDataBinder binder) {
|
|
// See Javadoc for supported pattern syntax
|
|
binder.setAllowedFields("firstName", "lastName", "*Address");
|
|
}
|
|
}
|
|
----
|
|
|
|
NOTE: The `disallowedFields` property has been
|
|
https://github.com/spring-projects/spring-framework/issues/36802[deprecated in Spring Framework 7.1]
|
|
because it is fragile and easy to get out of sync with the actual properties over time.
|
|
|
|
The patterns given to `allowedFields` and `disallowedFields` are not limited to top-level
|
|
field names. They are property paths, using the same syntax supported for reading and
|
|
writing bean properties elsewhere in the Framework. They also support `*` as a
|
|
wildcard; this means you can constrain binding more precisely:
|
|
|
|
* `"address"` matches the `address` property.
|
|
* `"person.address.city"` matches the `city` property of the nested `address` property of `person`.
|
|
* `"addresses[0].city"` matches the `city` property of the element at index `0` in the `addresses` array or `List`.
|
|
* `"map[key]"` matches the entry associated with `key` in the `map` property.
|
|
* `"map*"` matches every entry in the `map` property, such as `"map[key1]"` and `"map[key2]"`.
|
|
the same wildcard syntax also applies to indexed elements in an array or `List`.
|
|
|
|
See the {spring-framework-api}/validation/DataBinder.html#setAllowedFields(java.lang.String...)[`DataBinder#setAllowedFields`]
|
|
javadoc for further details on the supported pattern syntax.
|
|
|
|
By default, `DataBinder` applies both constructor and setter binding.
|
|
This is fine with immutable objects and dedicated objects, but for domain objects, you must
|
|
remember to set `allowedFields`. To ensure data binding is only used in declarative style where
|
|
expected inputs are explicitly declared, you can set `declarativeBinding` on `DataBinder`.
|
|
That applies constructor binding always, and setter binding conditionally if `allowedFields` is set.
|
|
The following shows how to set this flag globally, or
|
|
you can also narrow it through attributes on `ControllerAdvice`:
|
|
|
|
[source,java,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
@ControllerAdvice
|
|
public class ControllerConfig {
|
|
|
|
@InitBinder
|
|
void initBinder(WebDataBinder binder) {
|
|
binder.setDeclarativeBinding(true);
|
|
}
|
|
}
|
|
----
|