Mass Parameter Assignment
Overview
Many modern software development frameworks bind user input directly into internal objects. This is known as mass parameter assignment or auto-binding. While this feature is helpful to assign parameters to objects, an attacker can use it to write fields that should not be set by a user, leading to privilege escalation, data tampering, bypass of security mechanisms, and more.
For example, consider a Java Spring web application with a User
object:
public class User {
private String username;
private String password;
private String email;
private boolean isAdmin;
// Getters & Setters
}
The web application implements the following view:
<form action="/createUser" method="POST">
<input name="username" type="text">
<input name="password" type="text">
<input name="email" text="text">
<input type="submit" value="Create">
</form>
The controller that handles the creation request (Spring provides the automatic bind with the User
model):
@RequestMapping(value = "/createUser", method = RequestMethod.POST)
public String createUser(User user) {
userService.add(user);
return "successPage";
}
In this case, the browser sends the following request when the form is submitted:
POST /createUser HTTP/1.1
...
username=bob&password=supersecretpassword&email=bob@domain.test
Due to the auto-binding, an attacker can add the isAdmin
parameter to the request, which the controller will automatically bind to the model. As a result, the request below will create a user with administrative privileges.
POST /createUser HTTP/1.1
...
username=bob&password=supersecretpassword&email=bob@domain.test&isAdmin=true
This page contains recommendations for the implementation of protection against mass parameter assignment attacks.
General
Use Data Transfer Objects instead of binding parameters directly to internal objects.
If there is no possibility to use DTOs, use an allow list and non-sensitive parameters to restrict auto-binding only to those. Avoid using block lists.
Implement comprehensive input validation for each request parameter, see the Input Validation page.
Auto-binding allow list implementation
Gin Web Framework allows mass parameter assignment with functions such as Bind()
, shouldBind()
or mustBind()
. These functions rely on the form:
tag in a struct and only attributes tagged with form:
will be considered safe for auto-binding. Use the form
tag to mark parameters that are safe to be auto-bound.
For example, the User
struct below does not have the form:
tag for the IsAdmin
parameter. It means that IsAdmin
can not be auto-bound and used to elevate privileges as it is described in the Overview section:
package main
import (
"log"
"github.com/gin-gonic/gin"
)
type User struct {
Username string `form:"username"`
Password string `form:"password"`
Email string `form:"email"`
IsAdmin bool `default:false`
}
func main() {
route := gin.Default()
route.POST("/createUser", createUser)
route.Run()
}
func createUser(c *gin.Context) {
var user User
if c.ShouldBind(&user) == nil {
log.Println(user.Username)
log.Println(user.Password)
log.Println(user.Email)
log.Println(user.IsAdmin)
}
c.String(200, "Success")
}
References
Last updated