• Home   /  
  • Archive by category "1"

Mass Assignment Mvc

Last revision (mm/dd/yy): 12/21/2016

Introduction

Definition

Software frameworks sometime allow developers to automatically bind HTTP request parameters into program code variables or objects to make using that framework easier on developers. This can sometimes cause harm. Attackers can sometimes use this methodology to create new parameters that the developer never intended which in turn creates or overwrites new variable or objects in program code that was not intended. This is called a mass assignment vulnerability.

Alternative Names

Depending on the language/framework in question, this vulnerability can have several alternative names

  • Mass Assignment: Ruby on Rails, NodeJS
  • Autobinding: Spring MVC, ASP.NET MVC
  • Object injection: PHP

Example

Suppose there is a form for editing a user's account information:

<form> <input name=userid type=text> <input name=password type=text> <input name=email text=text> <input type=submit> </form>

Here is the object that the form is binding to:

public class User { private String userid; private String password; private String email; private boolean isAdmin; //Getters & Setters }

Here is the controller handling the request:

@RequestMapping(value = "/addUser", method = RequestMethod.POST) public String submit(User user) { userService.add(user); return "successPage"; }

Here is the typical request:

POST /addUser userid=bobbytables&password=hashedpass&email=bobby@tables.com

And here is the exploit:

POST /addUser userid=bobbytables&password=hashedpass&email=bobby@tables.com&isAdmin=true

Exploitability

This functionality becomes exploitable when:

  • Attacker can guess common sensitive fields
  • Attacker has access to source code and can review the models for sensitive fields
  • AND the object with sensitive fields has an empty constructor

Case Studies

GitHub

In 2012, GitHub was hacked using mass assignment. A user was able to upload his public key to any organization and thus make any subsequent changes in their repositories. GitHub's Blog Post

Solutions

  • Whitelist the bindable, non-sensitive fields
  • Blacklist the non-bindable, sensitive fields
  • Use Data Transfer Objects (DTOs)

General Solutions

Data Transfer Objects (DTOs)

An architectural approach is to create Data Transfer Objects and avoid binding input directly to domain objects. Only the fields that are meant to be editable by the user are included in the DTO.

public class UserRegistrationFormDTO { private String userid; private String password; private String email; //NOTE: isAdmin field is not present //Getters & Setters }

Language & Framework Specific Solutions

Spring MVC

Whitelisting

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

Reference

Blacklisting

@Controller public class UserController { @InitBinder public void initBinder(WebDataBinder binder, WebRequest request) { binder.setDisallowedFields(["isAdmin"]); } ... }

Reference

NodeJS + Mongoose

Whitelisting

var UserSchema = new mongoose.Schema({ userid  : String, password  : String, email  : String, isAdmin  : Boolean, }); UserSchema.statics = { User.userCreateSafeFields: ['userid', 'password', 'email'] }; var User = mongoose.model('User', UserSchema); _ = require('underscore'); var user = new User(_.pick(req.body, User.userCreateSafeFields));

ReferenceReference

Blacklisting

var massAssign = require('mongoose-mass-assign'); var UserSchema = new mongoose.Schema({ userid  : String, password  : String, email  : String, isAdmin  : { type: Boolean, protect: true, default: false } }); UserSchema.plugin(massAssign); var User = mongoose.model('User', UserSchema); /** Static method, useful for creation **/ var user = User.massAssign(req.body); /** Instance method, useful for updating **/ var user = new User; user.massAssign(req.body); /** Static massUpdate method **/ var input = { userid: 'bhelx', isAdmin: 'true' }; User.update({ '_id': someId }, { $set: User.massUpdate(input) }, console.log);

Reference

Ruby On Rails

Reference

Django

Reference

ASP.NET

Reference

PHP Laravel + Eloquent

Whitelisting

<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { private $userid; private $password; private $email; private $isAdmin; protected $fillable = array('userid','password','email'); }

Reference

Blacklisting

<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { private $userid; private $password; private $email; private $isAdmin; protected $guarded = array('isAdmin'); }

Reference

Grails

Reference

Play

Reference

Jackson (JSON Object Mapper)

ReferenceReference

GSON (JSON Object Mapper)

ReferenceReference

JSON-Lib (JSON Object Mapper)

Reference

Flexjson (JSON Object Mapper)

Reference

Authors and Primary Editors

References and future reading

Other Cheatsheets


Heads up!

The blog has moved!
The new URL to bookmark is http://blog.valeriogheri.com/

 

Following what happened to github in the past days (someone was able to hack a github repository exploiting a Ruby on Rails vulnerability to proof the point that this is in fact a vulnerability of the framework and a very dangerous one) there has been a lot of buzz and discussion in the web about  it and also about Asp.Net MVC framework, if it suffers from the same vulnerability and if it is to be considered a vulnerability in the first place.

What could actually happen using Asp.Net MVC model binding feature is explained very well in this blog article by Josh Bush, so I won’t repeat it.

A good solution to this problem is already offered by the framework, DataAnnotations! I’m using the same ViewModel as in Josh Bush’s example, with an extra row at the beginning:

[Bind(Exclude = "IsAdmin")] public class User { public int Id { get; set; } public string UserName { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public bool IsAdmin { get; set; } }

By using the Bind attribute, [Bind(Exclude = “IsAdmin”)], we are explicitly asking the framework not to update the value of property IsAdmin when we use the UpdateModel(user) instruction.

So even if the attacker will attempt to change the query string in the URL, the Model Binder will simply not use it for this particular property and your system will be “safe”!

Valerio

Like this:

LikeLoading...

Related

One thought on “Mass Assignment Mvc

Leave a comment

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *