Preventing Mass Assignment Attacks in Spring

If you have a wizard to collect data from users in a set of steps you can open yourself up to a mass assignment attack. OWASP as always gives great information on this.

How it works

You Bind an object to the model and you want to populate the fields in that object as your user progresses through your wizard. So on the first screen you might collect their name, second screen email and so on. Between each of these steps you perform validation on the just entered values.

However a hacker exploiting mass assignment can bind data from step 1 during a subsequent step just by putting the variable and value in the URL (assuming GET, although obviously this can be done with POST also).

So for the first step you are after this:

https://mywebsite.com/myapp/action?email=anthonynolan@somemail.com

And the second step, this:

https://mywebsite.com/myapp/action2?name=Anthony

Instead the hacker supplies this which is fine and passes our validation:

https://mywebsite.com/myapp/action?email=anthonynolan@somemail.com

Followed by this. Which is not fine as the email is not validated on this step:

https://mywebsite.com/myapp/action2?name=Anthony&email=bad_guy_email@dodgy.com

Because Spring binds all params that it can match in the URL the email address will be bound in the last case. Your code may not have included validation of email (restricted domains for example) in that step of the wizard.

There are a number of approaches to fix this.

Repeat the validations on each step

Therefore the validation is accretive. Something like this.

Step 1

  • Validate condition 1

Step2

  • Validate condition 1 again
  • Validate condition 2
and so on.

This leads to some duplication of code - but it is very minimal - only method calls. I plan to put together a neater way of achieving this accretion, but for now this will do.

Isolate each wizard step in its own controller

This will allow you to use the OWASP recommended method of using a binder (this is the whitelist version, there is blacklist too):

@Controller
  public class UserController
  {
     @InitBinder
     public void initBinder(WebDataBinder binder, WebRequest request)
     {
        binder.setAllowedFields(["userid","password","email"]);
     }
  
     ...
  }

However if you have the steps in the same controller (a better design in my opinion), this won't work. You will end up blocking the params at every step, not just the prohibited ones.

Blacklist params in handler

You can however use the Params attribute on your RequestMapping annotation to disallow certain parameters. This one will disallow role in the params list. If role is supplied the user will get a 404.

@RequestMapping(value = "/bitofurl", params = "!role")


All this is a little awkward and removes some of the elegance of a Spring solution. But mass assignment attacks are serious stuff and can result in all manner of nastiness. Better slightly less elegant code than a compromised user DB.



Comments

Popular posts from this blog

Building a choropleth map for Irish agricultural data

Early Stopping with Keras

AutoCompleteTextView backed with data from SQLite in Android