Reputation: 1961
I have an ASP.NET CORE Web API app and placed a Model as:
public class SamplePayload
{
public string Attribute1 { get; set; }
public string Attribute2 { get; set; }
}
then my controller looks like:
[ApiController]
public class SampleController : ControllerBase
{
[HttpPost]
public async Task<string> Add(SamplePayload samplePayload)
{
if (!ModelState.IsValid)
{
//Throw Error
}
return "Hello";
}
}
However, the Action still accepts the payload if the Request Body had its payload like this (with additional attributes):
{
"Attribute1":"Value1",
"Attribute2":"Value2",
"EvilAttribute":"EvilValue"
}
As you see, EvilAttribute
is not a valid attribute according to the Model, but still, the controller accepts it, and Model.IsValid
also returns true
despite the fact that I have [ApiController]
assigned on top of the controller.
My question is how can I do validation to check that only attributes defined in the Model need to be passed in the Request body? Doesn't ASP.NET core offer simpler handling?
Note:
The reason for this requirement is, Under a Vulnerability assessment done by an independent assessor, highlighted that my Endpoint
accepts additional parameters in request body
The Assessment quoted as:
- Test Category: Mass Assignment;
- Test Conducted: Adding additional parameters to the requests
- Findings: Additional parameters accepted with a request body
Recommendations:
- If possible, avoid using functions that automatically bind a client's input into code variables or internal objects.
- Whitelist only the properties that should be updated by the client.
- If applicable, explicitly dene and enforce schemas for the input data payloads.
Upvotes: 0
Views: 9343
Reputation: 11100
An [ApiController]
or a parameter marked as [FromBody]
will be serialised in MVC via an input formatter, rather than binding from a value provider.
Working backwards from the mvc source code. It looks like you can control MVC's serialisation settings if you are using System.Text.Json, though I don't see a way to reject extra values;
services.Configure<JsonOptions>(o =>
{
});
Or newtonsoft, which does seem to allow rejecting extra values;
services.Configure<MvcNewtonsoftJsonOptions>(o =>
{
o.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;
});
(I haven't tested this myself though...)
I would still push back on this "security" assessment. If you don't have any extra fields available to bind, then rejecting requests doesn't improve security. Though it may help consumers to understand if they have mis-spelled an attribute name.
Upvotes: 2
Reputation: 21383
Please check this article: Model Binding in ASP.NET Core
Model binding tries to find values for the following kinds of targets:
- Parameters of the controller action method that a request is routed to.
- Parameters of the Razor Pages handler method that a request is routed to.
- Public properties of a controller or PageModel class, if specified by attributes.
For your scenario, if you set a break point in the Add method, you can see that the Model Binding will just find values based on the SamplePayload's properties.
So, I think there is no need to check whether the request body contains more data or not.
Upvotes: 1
Reputation: 3880
I see not much benefits from rejecting the requests that have more data in it.
If that is some sort of requirement, here is what you can try:
I think you may need to implement your own ModelBinder
as per example described here:
https://learn.microsoft.com/en-US/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-5.0
The way default model binding works - is going from Model perspective and search for matching fields in the request and assigns values to related model properties.
Once the model that is required can be constructed and passes all of it's internal constraints - it is Valid.
Upvotes: 2