假设我有一条看起来像/controller/action/UserID
的路线,可以接受POST。
然后假设某人发布到该URL,并且将名为UserID的变量设置为其他名称。
我想弄清楚的是,是否存在一个安全问题,其中一个值“偷偷摸摸”通过了我进行的权限检查。
参数源优先级的顺序由ValueProviderFactories.Factories
集合确定,其中(默认情况下)在模型绑定期间POST版本的参数优先于路由数据。
因此,如果有人将User ID = 666 POST到控制器/controller/action/777
中的UserId
URL,则为666。
本文的Value Providers部分很好地概述了其工作原理:
在运行时,ASP.NET MVC使用在ValueProviderFactories类评估模型的请求值粘合剂可以使用。
默认情况下,值提供者集合从各种资源按以下顺序排列:
- 先前绑定的动作参数,当该动作是子动作时动作
- 表单字段(
Request.Form
)- JSON中的属性值请求正文(
Request.InputStream
),但仅当请求为AJAX请求- 路由数据(
RouteData.Values
)- 查询字符串参数(
Request.QueryString
)- 已发布文件(
Request.Files
)
不管参数优先级如何,您都应检查用户是否有权访问所有POST和GET上的指定UserID
。
用户可以轻松地潜入一个额外的UserID
参数,就像将形式action
更改为路径中带有其他UserID
的URL一样,因为这些只是客户端变量。
<form method="post" action="/controller/action/1">
很容易更改为
客户端上的<form method="post" action="/controller/action/2">
。
这就像添加一个隐藏字段一样简单:<form method="post" action="/controller/action/1"> <input type="hidden" name="UserID" value="2" />
如果您的控制器方法签名是
[HttpPost]
public ActionResult Foo(model model, int userId)
并且您仅在输入参数中使用userId
(例如,不直接访问Request.Form
或model
中的值),那么参数优先级是什么都没有关系。您应该验证当前登录的用户是否有权查看或编辑控制器POST方法中的userId
ID,因为无论如何都不能信任所有客户端提供的参数。
例如
[HttpPost]
public ActionResult Foo(model model, int userId)
{
if (CurrentUserHasPermissionToEdit(userId))
{
// Do stuff
}
else
{
// Reject
}
}