In order to reduce the work for developers, many frameworks provide convenient mass-assignment functionality. This lets developers inject an entire set of user-entered data from a form directly into an object or database. Without it, developers would be forced to tediously add code specifically for each field of data, cluttering the code base with repeated form mapping code.
The downside of this functionality is that it is often implemented without a whitelist that prevents users from assigning data to protected fields. An attacker may exploit this vulnerability to gain access to sensitive data or to cause data loss.
As demonstrated by prominent cases, even the best teams of developers can miss this non-obvious vulnerability.
In this example, a web shop allows users to sign up and keep track
of their orders. The owner of the web shop has a special administrator
account that allows them to manage other users and their orders. The
administrator account is created in the database, just like a regular
user account, except it has an is_administrator
flag set.
On the sign up page, the user is asked to enter their email address and select a password:
<form method="post" action="/signup">
<p>
Enter your email address:
<input type="text" name="user[email]">
</p>
<p>
Select a password:
<input type="password" name="user[password]">
</p>
<input type="submit" value="Sign up">
</form>
The corresponding controller action creates the user in the database:
def signup
@user = User.create(params[:user])
# => User<email: "[email protected]", password: "qwerty", is_administrator: false>
end
An attacker may inject their own HTML into form (or otherwise modify the request):
<form method="post" action="/signup">
<!-- INJECTED FIELD: -->
<input type="hidden" name="is_administrator" value="true">
<p>
Enter your email address:
<input type="text" name="user[email]">
</p>
<p>
Select a password:
<input type="password" name="user[password]">
</p>
<input type="submit" value="Sign up">
</form>
The controller action will create the user, letting the attacker gain complete control of the web shop:
def signup
@user = User.create(params[:user])
# => User<email: "[email protected]", password: "qwerty", is_administrator: true>
end
In the example above, the developer should change the code to either explicitly assign the attributes for the allowed fields, or use a whitelisting function provided by the framework (Ruby on Rails in this case):
def signup
# Explicit assignment:
@user = User.create(
email: params[:user][:email],
password: params[:user][:password]
)
# or whitelisting:
@user = User.create(
params.require(:user).permit(:email, :password)
)
end
More useful information may be found at:
We provide code security reviews as a service. Based on our extensive experience in the field of sofware engineering and IT security, we know how to efficiently review entire code bases and identify security critical parts of the software.
This enables us to provide our security code review service at a fixed rate per review, providing our customers a transparent, efficient and reliable process.
Fixed Price per Review