【问题标题】:Securing ASP.NET MVC3 Controllers/Actions保护 ASP.NET MVC3 控制器/操作
【发布时间】:2011-07-05 17:57:14
【问题描述】:

我正在设计一个 MVC 3 应用程序,其中多个租户驻留在一个数据库中。

防止用户在 MVC 中编辑/查看其他租户数据的最佳方法是什么? (即有人可以输入“/People/Edit/1”并编辑 ID 为 1 的人——无论他们是否是租户数据的一部分)。

我知道我可以为每个控制器覆盖“OnActionExecuting(ActionExecutingContext filterContext)” - 但是必须单独处理每个操作听起来很疯狂,根据它是 POST 还是 GET 来获取 ID 或 OBJECT,然后检查操作是否是允许的。

有更好的想法吗?

另外,我不想为每个租户创建不同的数据库或架构。

提前致谢。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 security


    【解决方案1】:

    不要将 id 传递给您的控制器操作,而是为您的实体编写一个自定义模型绑定器,该绑定器将从数据库中获取它。因此,例如让我们假设您有以下模型:

    public class Person
    {
        public string Id { get; set; }
        ... some other properties
    }
    

    现在而不是:

    [HttpPost]
    public ActionResult Edit(string id)
    {
        ...
    }
    

    写:

    [HttpPost]
    public ActionResult Edit(Person person)
    {
        ...
    }
    

    然后为 Person 编写一个自定义模型绑定器:

    public class PersonModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var id = bindingContext.ValueProvider.GetValue("id");
            // check if an id was provided and if the user is authenticated
            if (!controllerContext.HttpContext.User.Identity.IsAuthenticated || id == null)
            {
                throw new HttpException(403, "Forbidden");
            }
            var currentUser = controllerContext.HttpContext.User.Identity.Name;
            // fetch the person from your repository given the id and belonging 
            // to the currently authenticated user
            var person = _repository.GetPerson(id.AttemptedValue, currentUser);
            if (person == null)
            {
                // no person found matching
                throw new HttpException(403, "Forbidden");
            }
            return person;
        }
    }
    

    您将在Application_Start注册:

    ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder());
    

    【讨论】:

    • 谢谢达林。这听起来是个好主意,但我不必替换所有获取和发布对象的逻辑。
    【解决方案2】:

    原答案

    要快速解决问题,请使用 guid 而不是自动增加的整数。然而,这只是在拖延问题。

    您可以做的其中一件事是角色您自己的授权属性http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.aspx 或者您可以选择创建一个全局操作过滤器。 http://www.asp.net/mvc/tutorials/understanding-action-filters-cs

    根据评论中的要求添加有关如何执行此操作的信息

    public class MySuperFilter : ActionFilterAttribute
        {
            //Called by the MVC framework before the action method executes.
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                String user = filterContext.HttpContext.User.Identity.Name;
                int id = int.Parse(filterContext.RouteData.GetRequiredString("Id"));
                if (!IsValidUser(user,id))
                {
                    filterContext.Result = new RedirectToRouteResult(
                            new RouteValueDictionary {{ "Controller", "YourController" },
                                          { "Action", "YourAction" } });
    
    
                }
    
                base.OnActionExecuting(filterContext);
            }
    
            private bool IsValidUser(string user,int id)
            {
                //Check if the user has acces to the page
                return true;
            }
        }
    

    【讨论】:

    • 这个方法很有意义,听起来是最容易实现的。一个问题:我想查看一个人(例如,Id = 3)。详细信息操作有我的新过滤器 [CanViewPerson]。如何让覆盖函数知道我想查看 Id = 3 的人?
    • 感谢您更新的答案。现在说得通了。如果我将 [ValidateAntiForgeryToken] 属性和令牌添加到我的表单中,我是否正确地说这将解决我的所有 GET 请求和我的 POST 请求的安全问题?
    • 该令牌仅检查是否有人没有交替页面。防止addons.mozilla.org/en-US/firefox/addon/tamper-data 类型的攻击。您应该是安全的,但我认为仍然可以通过 php.net/manual/en/intro.curl.php 访问您的后期请求
    • Cheers Dvd,知道如何防止请求后攻击吗?
    • @ViperMan 将属性放在 post 上并获取方法
    【解决方案3】:

    这是一个不优雅的解决方案,但根据范围,它可能是最简单的。设计了一个类似的系统,它对多个租户数据的入口点相对较少,我们只需检查 CurrentUser 是否是正在查询的对象的所有者。我们使用的对象是一个具有所有者字段的公共基础接口,因此检查不是针对特定对象进行的,而只是来自接口。如果存在不匹配,我们会抛出安全异常并记录用户可能正在使用查询字符串,看看他们是否让我们的网站像许多生产网站那样泄露数据。

    【讨论】:

    • 看来你是对的。我希望有一个更优雅的解决方案,但有时你必须适应你所拥有的。
    • @ViperMAN 我自己也是一名建筑师真的只是针对少数几件事。如果您有几十个需要类似保护的操作,我肯定会考虑使用 ActionFilter 以更 AOP 的方式进行操作。 ActionFilters 是我只在 MVC3 中开发的原因,因为它们允许真正的 AOP,可以实现几乎 PostSharp 级别的灵活性,但没有构建时间开销。
    • 非常正确。我走的是 ActionFilter 路线——正如你所说,这对 AOP 来说要好得多。
    猜你喜欢
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多