如何创建特定于区域、控制器和操作的自定义 AuthorizeAttribute? [英] How do I create a custom AuthorizeAttribute that is specific to the area, controller and action?

查看:19
本文介绍了如何创建特定于区域、控制器和操作的自定义 AuthorizeAttribute?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

换句话说,这是一个非常愚蠢的想法吗?

In other words, is this a really stupid idea?

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeActionAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        // get the area, controller and action
        var area = filterContext.RouteData.Values["area"];
        var controller = filterContext.RouteData.Values["controller"];
        var action = filterContext.RouteData.Values["action"];
        string verb = filterContext.HttpContext.Request.HttpMethod;

        // these values combined are our roleName
        string roleName = String.Format("{0}/{1}/{2}/{3}", area, controller, action, verb);

        // set role name to area/controller/action name
        this.Roles = roleName;

        base.OnAuthorization(filterContext);
    }
}

更新在我们拥有极其精细的角色权限的情况下,我试图避免以下情况,因为角色是基于每个客户端设置并附加到用户组的:

UPDATE I'm trying to avoid the following, in a scenario where we have extremely granular role permissions because the roles are setup on a per-client basis and attached to user groups:

public partial class HomeController : Controller
{
    [Authorize(Roles = "/supplierarea/homecontroller/indexaction/")]
    public virtual ActionResult Index()
    {
        return View();
    }

    [Authorize(Roles = "/supplierarea/homecontroller/aboutaction/")]
    public virtual ActionResult About()
    {
        return View();
    }
}

谁能告诉我一种编写此 AuthorizeRouteAttribute 以访问路由信息并将其用作角色名称的安全方法?正如 Levi 所说,RouteData.Values 并不安全.

Can anyone enlighten me to a secure way to write this AuthorizeRouteAttribute to access the route information and use this as the role name? As Levi says, the RouteData.Values isn't secure.

使用执行的 httpContext.Request.Path 是否更安全或更好的做法?

Is the use of the executing httpContext.Request.Path any more secure or better practice?

public override void OnAuthorization(AuthorizationContext filterContext)
{
    if (filterContext == null)
    {
        throw new ArgumentNullException("filterContext");
    }

    if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
    {
        // auth failed, redirect to login page
        filterContext.Result = new HttpUnauthorizedResult();
        return;
    }

    var path = filterContext.HttpContext.Request.Path;
    var verb = filterContext.HttpContext.Request.HttpMethod;

    // these values combined are our roleName
    string roleName = String.Format("{0}/{1}", path, verb);

    if (!filterContext.HttpContext.User.IsInRole(roleName))
    {
        // role auth failed, redirect to login page
        filterContext.Result = new HttpUnauthorizedResult();
        // P.S. I want to tell the logged in user they don't 
        // have access, not ask them to login. They are already
        // logged in!
        return;
    }

    //
    base.OnAuthorization(filterContext);
}

这也许更能说明问题:

enum Version
{
    PathBasedRole,
    InsecureButWorks,
    SecureButMissingAreaName
}

string GetRoleName(AuthorizationContext filterContext, Version version)
{
    //
    var path = filterContext.HttpContext.Request.Path;
    var verb = filterContext.HttpContext.Request.HttpMethod;

    // recommended way to access controller and action names
    var controller = 
        filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
    var action = 
        filterContext.ActionDescriptor.ActionName;
    var area = "oh dear...."; // mmmm, where's thearea name???

    //
    var insecureArea = filterContext.RouteData.Values["area"];
    var insecureController = filterContext.RouteData.Values["controller"];
    var insecureAction = filterContext.RouteData.Values["action"];

    string pathRoleName = 
        String.Format("{0}/{1}", path, verb);
    string insecureRoleName = 
        String.Format("{0}/{1}/{2}/{3}", 
        insecureArea, 
        insecureController, 
        insecureAction, 
        verb);
    string secureRoleName = 
        String.Format("{0}/{1}/{2}/{3}", 
        area, 
        controller, 
        action, 
        verb);

    string roleName = String.Empty;

    switch (version)
    {
        case Version.InsecureButWorks:
            roleName = insecureRoleName;
            break;
        case Version.PathBasedRole:
            roleName = pathRoleName; 
            break;
        case Version.SecureButMissingAreaName:
            // let's hope they don't choose this, because
            // I have no idea what the area name is
            roleName = secureRoleName;
            break;
        default:
            roleName = String.Empty;
            break;
    }

    return roleName;
}

推荐答案

不要这样做.

如果确实需要,可以使用控制器的Type 或操作的MethodInfo 来做出安全决策.但是,一切都建立在字符串的基础上是自找麻烦.请记住,路由值与实际控制器的映射不能保证 1:1.如果您使用路由元组 (a, b, c) 来验证对 SomeController::SomeAction 的访问,但有人发现 (a, b', c) 也执行了相同的操作,则该人可以绕过您的安全机制.

If you really need to, you can use the Type of the controller or the MethodInfo of the action to make security decisions. But basing everything off of strings is asking for trouble. Remember, there's no guaranteed 1:1 mapping of Routing values to actual controller. If you're using the Routing tuple (a, b, c) to validate access to SomeController::SomeAction but somebody discovers that (a, b', c) also hits that same action, that person can bypass your security mechanisms.

编辑以回复评论:

您可以通过 filterContext 参数的 ActionDescriptor 属性访问控制器的 Type 和操作的 MethodInfo.这是确定在 MVC 管道处理时真正执行什么操作的唯一可靠方法,因为您的查找可能与 MVC 幕后发生的事情不完全匹配.一旦你有了 Type/MethodInfo/不管什么,你就可以使用任何你想要的信息(例如它们的完全限定名称)来做出安全决定.

You have access to the controller's Type and the action's MethodInfo via the filterContext parameter's ActionDescriptor property. This is the only sure-fire way to determine what action will really execute when the MVC pipeline is processing, because it's possible that your lookup doesn't exactly match what's going on behind the scenes with MVC. Once you have the Type / MethodInfo / whatever, you can use whatever information you wish (such as their fully-qualified names) to make security decisions.

作为一个实际的例子,考虑一个带有控制器 FooController 和一个动作 TheAction 的区域 MyArea.通常你会点击这个 FooController::TheAction 的方式是通过这个 URL:

As a practical example, consider an area MyArea with a controller FooController and an action TheAction. Normally the way that you would hit this FooController::TheAction is via this URL:

/MyArea/Foo/TheAction

/MyArea/Foo/TheAction

Routing 给出了元组 (Area = "MyArea", Controller = "Foo", Action = "TheAction").

And Routing gives the tuple (Area = "MyArea", Controller = "Foo", Action = "TheAction").

但是,您也可以通过此 URL 访问 FooController::TheAction:

However, you can also hit FooController::TheAction via this URL:

/Foo/TheAction

/Foo/TheAction

并且路由会给出元组(Area = "",Controller = "Foo",Action = "TheAction").请记住,区域与路由相关联,而不是与控制器相关联.而且由于一个控制器可以被多个路由命中(如果定义匹配),那么一个控制器也可以在逻辑上与多个区域相关联.这就是为什么我们告诉开发人员永远不要使用路线(或区域或 <location> 标签,通过扩展)来做出安全决策.

And Routing will give the tuple (Area = "", Controller = "Foo", Action = "TheAction"). Remember, areas are associated with routes, not controllers. And since a controller can be hit by multiple routes (if the definitions match), then a controller can also be logically associated with multiple areas. This is why we tell developers never to use routes (or areas or the <location> tag, by extension) to make security decisions.

此外,您的类中存在一个错误,即它是可变的(它在 OnAuthorization 中改变了自己的 Roles 属性).动作过滤器属性必须是不可变的,因为它们可能被部分管道缓存并重用.根据在您的应用程序中声明此属性的位置,这会引发计时攻击,然后恶意网站访问者可以利用该攻击来授予自己访问他希望执行的任何操作的权限.

Additionally, there's a bug in your class in that it's mutable (it mutates its own Roles property in OnAuthorization). Action filter attributes must be immutable, since they may be cached by parts of the pipeline and reused. Depending on where this attribute is declared in your application, this opens a timing attack, which a malicious site visitor could then exploit to grant himself access to any action he wishes.

有关更多信息,另请参阅我的回复:

For more info, see also my responses at:

这篇关于如何创建特定于区域、控制器和操作的自定义 AuthorizeAttribute?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆