Mass Assignment Cheat Sheet / 大量赋值攻击技巧概览¶
Introduction / 介绍¶
Definition / 定义¶
Software frameworks sometimes 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.
软件框架有时允许开发者自动将 HTTP 请求参数绑定到程序代码变量或对象中,以便使框架更容易使用。这有时会造成危害。
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.
中文:大量赋值:Ruby on Rails, NodeJS. - Autobinding: Spring MVC, ASP NET MVC.
中文:自动绑定: Spring MVC, ASP.NET MVC. - Object injection: PHP.
中文:对象注入: 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 in which we set the value of the attribute isAdmin of the instance of the class User:
以下是设置类User实例的属性isAdmin值的漏洞利用:
POST /addUser
...
userid=bobbytables&password=hashedpass&email=bobby@tables.com&isAdmin=true
Exploitability / 可利用性¶
Mass assignment is exploitable when attacker-controlled input can initialize or update fields that the caller is not authorized to change, such as a role or account owner. Field names may be guessed or discovered; source-code access is not required. CWE-915 defines the weakness in terms of insufficient control over writable attributes.
An empty constructor is not a general prerequisite. For example, Spring supports both constructor and setter binding. Review which inputs the binding mechanism exposes, including nested objects.
GitHub case study¶
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¶
- Prefer dedicated input objects, such as Data Transfer Objects (DTOs), containing only fields the caller may edit; see Spring's model design guidance.
中文:优先使用仅包含调用者可能编辑的字段的专用输入对象,例如数据传输对象 (DTO);参见 Spring 的模型设计指南。 - Explicitly allow-list fields when binding to an object with additional properties.
- Do not rely on a block-list as the sole protection: a new or overlooked sensitive field remains bindable. CWE-915 recommends allowlists over denylists. The block-list examples below illustrate mechanisms encountered in existing applications, not the recommended design.
中文:不要仅依赖阻止列表作为唯一的保护措施:新的或被忽视的敏感字段仍然可以绑定。CWE-915 建议使用允许列表而不是阻止列表。下面的阻止列表示例说明了现有应用程序中遇到的机制,而不是推荐的设计。
DTOs and field allowlists restrict writable properties; they do not replace authorization for the requested object and operation.
General Solutions¶
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.
架构方法之一是创建数据传输对象,并避免直接将输入绑定到领域对象。仅包含用户可编辑的字段在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¶
Allow-listing / 允许列表¶
@Controller
public class UserController
{
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request)
{
binder.setAllowedFields("userid", "password", "email");
}
...
}
See Spring's model design guidance for dedicated input objects and allowed fields.
参见Spring的模型设计指南,了解专用输入对象和允许的字段。
Block-listing / 阻止列表¶
Spring describes disallowedFields as fragile because fields can be missed or added later. Prefer the allow-list above; this example only excludes the named property.
Spring将disallowedFields描述为脆弱,因为字段可能会被遗漏或后来添加。优先考虑上面的允许列表;此示例仅排除指定的属性。
@Controller
public class UserController
{
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request)
{
binder.setDisallowedFields("isAdmin");
}
...
}
See the Spring data binding limitations.
参见Spring数据绑定限制。
NodeJS + Mongoose¶
Allow-listing / 允许列表¶
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));
Take a look here for the documentation.
查阅此处获取文档信息。
Block-listing / 阻止列表¶
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);
Take a look here for the documentation.
查阅此处获取文档信息。
Ruby On Rails¶
Take a look here for the documentation.
查阅此处获取文档信息。
Django¶
Take a look here for the documentation.
查阅此处获取文档信息。
ASP NET¶
Take a look here for the documentation.
查看此处以获取文档信息。
PHP Laravel + Eloquent¶
Allow-listing / 允许列表¶
<?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');
}
Take a look here for the documentation.
查看此处以获取文档信息。
Block-listing / 阻止列表¶
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
private $userid;
private $password;
private $email;
private $isAdmin;
protected $guarded = array('isAdmin');
}
Take a look here for the documentation.
查看此处以获取文档信息。
Grails¶
Take a look here for the documentation.
查看此处以获取文档信息。
Play¶
Take a look here for the documentation.
查看此处以获取文档信息。
Jackson (JSON Object Mapper) / Jackson (JSON 对象映射器)¶
Take a look here and here for the documentation.
GSON (JSON Object Mapper) / GSON (JSON 对象映射器)¶
Take a look here and here for the document.
JSON-Lib (JSON Object Mapper) / JSON-Lib (JSON 对象映射器)¶
Take a look here for the documentation.
查看此处的文档。
Flexjson (JSON Object Mapper) / Flexjson (JSON 对象映射器)¶
Take a look here for the documentation.
查看此处的文档。
References / 参考¶
- Ruby on Rails: Strong Parameters) (Ruby on Rails: 强参数)
- Spring Framework: DataBinder Security Considerations) (Spring框架:DataBinder安全注意事项)