hiFI
hiFI

Reputation: 1961

How to Validate Request Body by allowing only attributes assigned in the Model of an asp.net core web api app

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

Answers (3)

Jeremy Lakeman
Jeremy Lakeman

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

Zhi Lv
Zhi Lv

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.

enter image description here

So, I think there is no need to check whether the request body contains more data or not.

Upvotes: 1

madoxdev
madoxdev

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

Related Questions