[ 
https://issues.apache.org/jira/browse/WW-5624?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Lukasz Lenart updated WW-5624:
------------------------------
    Description: 
h2. Summary

{{@StrutsParameter}} enforcement is currently implemented in 
{{ParametersInterceptor}} for standard request parameter binding, but 
request-body based binders in some plugins bypass that authorization model and 
populate action/model objects directly.

This creates inconsistent behavior between URL/form parameters and JSON/XML 
request bodies, and may allow mass assignment of properties that would normally 
be rejected by {{ParametersInterceptor}}.

h2. Affected areas currently identified

* JSON plugin:
{{JSONPopulator.populateObject()}} sets properties via direct reflection and 
does not follow the full {{@StrutsParameter}} authorization rules.

* REST plugin:
{{JacksonJsonHandler.toObject()}} updates target objects directly via Jackson 
and does not follow the full {{@StrutsParameter}} authorization rules.

h2. Problem scope

The issue is broader than checking whether a setter is annotated. The current 
core contract in {{ParametersInterceptor}} also includes:

* permitted nesting depth
* authorization based on the exposed root member
* ModelDriven handling
* transition mode semantics
* related allowlisting behavior

Any request-body binding implementation should align with that same contract, 
otherwise Struts applies different security rules depending on how input 
reaches the action/model.

h2. Expected direction

Instead of implementing separate partial checks in each plugin, Struts should 
reuse or extract the shared parameter-binding authorization logic from 
{{ParametersInterceptor}} and apply it consistently across request-body binders.

  was:
h2. Summary

{{JSONPopulator.populateObject()}} in the struts2-json-plugin sets action 
properties via direct Java reflection ({{{}Method.invoke(){}}}) without 
checking the {{@StrutsParameter}} annotation. This bypasses the parameter 
allowlisting that {{ParametersInterceptor}} enforces for URL parameters, 
enabling mass assignment of unannotated properties via JSON request body.

{{JacksonJsonHandler.toObject()}} in the struts2-rest-plugin uses 
{{ObjectMapper.readerForUpdating(target).readValue(reader)}} to merge JSON 
request body directly into the action object. Jackson sets any field with a 
matching setter, completely bypassing the {{@StrutsParameter}} annotation check 
that {{ParametersInterceptor}} enforces for URL parameters. This enables mass 
assignment of unannotated properties via REST JSON request body.
h2. Changes
 * {*}JSONPopulator.java{*}: Add {{@StrutsParameter}} annotation check before 
{{{}Method.invoke(){}}}. When {{struts.parameters.requireAnnotations}} is 
enabled and the setter lacks the annotation, the property is skipped with a 
debug log message.
 * {*}JSONInterceptor.java{*}: Wire the 
{{struts.parameters.requireAnnotations}} setting via {{@Inject}} into 
{{{}JSONPopulator.setRequireAnnotations(){}}}.
 * {*}JacksonJsonHandler.java{*}: When {{struts.parameters.requireAnnotations}} 
is enabled, deserialize JSON into a map first, then filter properties against 
the {{@StrutsParameter}} annotation on the target class's setter methods before 
setting them. When disabled, preserve the original {{readerForUpdating()}} 
merge for backwards compatibility.

h2. Impact

Without this fix:
 * URL params to unannotated setters: *BLOCKED* (ParametersInterceptor enforces)
 * JSON body to same unannotated setters: *BYPASSES* (JSONPopulator ignores 
annotation)

With this fix, both pathways consistently enforce {{{}@StrutsParameter{}}}.
h2. REFER

[https://github.com/apache/struts/pull/1651]

[https://github.com/apache/struts/pull/1652]

[https://github.com/apache/struts/pull/1651/changes/03a07b871ac82d8955b310155b3cbe1e30c861b3]

https://github.com/apache/struts/pull/1652/changes/d4b01caded8453bc3d02bd6ecff72e264dc81dd0


> Request body population bypasses @StrutsParameter contract outside 
> ParametersInterceptor
> ----------------------------------------------------------------------------------------
>
>                 Key: WW-5624
>                 URL: https://issues.apache.org/jira/browse/WW-5624
>             Project: Struts 2
>          Issue Type: Bug
>          Components: Plugin - JSON, Plugin - REST
>    Affects Versions: 7.1.1
>            Reporter: Tran Quac
>            Priority: Major
>             Fix For: 7.2.0
>
>
> h2. Summary
> {{@StrutsParameter}} enforcement is currently implemented in 
> {{ParametersInterceptor}} for standard request parameter binding, but 
> request-body based binders in some plugins bypass that authorization model 
> and populate action/model objects directly.
> This creates inconsistent behavior between URL/form parameters and JSON/XML 
> request bodies, and may allow mass assignment of properties that would 
> normally be rejected by {{ParametersInterceptor}}.
> h2. Affected areas currently identified
> * JSON plugin:
> {{JSONPopulator.populateObject()}} sets properties via direct reflection and 
> does not follow the full {{@StrutsParameter}} authorization rules.
> * REST plugin:
> {{JacksonJsonHandler.toObject()}} updates target objects directly via Jackson 
> and does not follow the full {{@StrutsParameter}} authorization rules.
> h2. Problem scope
> The issue is broader than checking whether a setter is annotated. The current 
> core contract in {{ParametersInterceptor}} also includes:
> * permitted nesting depth
> * authorization based on the exposed root member
> * ModelDriven handling
> * transition mode semantics
> * related allowlisting behavior
> Any request-body binding implementation should align with that same contract, 
> otherwise Struts applies different security rules depending on how input 
> reaches the action/model.
> h2. Expected direction
> Instead of implementing separate partial checks in each plugin, Struts should 
> reuse or extract the shared parameter-binding authorization logic from 
> {{ParametersInterceptor}} and apply it consistently across request-body 
> binders.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to