基于路由值的 AuthAttribute 安全修剪 MVC 站点地图提供程序节点

Security Trimming MVC Sitemap Provider Nodes With AuthAttribute Based on Route Values

我们有一个完整的站点地图,其中有数百个节点在操作上配置了站点地图属性。这些节点是根据声明进行安全修整的,可以完美地工作。一切都很好而且很快。

我们现在要求根据路由值无法访问某些页面。基本上根据路由中 personId 的值隐藏 mvc 菜单链接。使用以下代码:

//Just proof of concept - people restricted will be from a service
public class PersonAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (!httpContext.Request.RequestContext.RouteData.Values.ContainsKey("personId"))
        {
            return base.AuthorizeCore(httpContext);
        }
        var personId = httpContext.Request.RequestContext.RouteData.Values["personId"].ToString();
        int value;
        int.TryParse(personId, out value);
        if (value != 0 && value == 3708)
        {
            return false;
        }
        return base.AuthorizeCore(httpContext);
    }
}

这在阻止访问方面非常有效。然而,与我们的其他安全修整站点地图不同的是,它不适用于此。如果我首先访问受限制的人,它会隐藏该人和其他所有人的节点。如果我访问一个非隐藏的人,那么每个人都可以看到该节点,但是如果我尝试访问他们的节点,我会收到拒绝访问该人的请求。

我认为这与节点没有基于路由值进行修剪的概念有关。

关于如何实施的任何想法。我们正在尝试实施更灵活的安全模型。

由于 MVC 和 MvcSiteMapProvider 使用 AuthorizeAttribute.

的方式不同,此处存在断开连接

在 MVC 中,AuthorizeAttribute 只是根据当前请求的上下文进行检查。当前上下文包含确定用户是否有权查看当前页面所需的一切。

MvcSiteMapProvider 检查每个请求的每个 节点。因此,我们不能做出相同的假设,即当前上下文是正确的,以确定节点是可访问的。为每个节点创建了一个新的临时HttpContext(基于节点生成的URL)并且检查期间使用的路由值来自该上下文(而不是当前上下文)。

这个假的HttpContext并不完美。 Microsoft 已经创建了几个冗余属性 HttpContextRequestContext 等,必须显式设置,否则它们将默认为当前上下文,并且并非所有属性都已被 AuthorizeAttributeAclModule 设置。在这种情况下,这是有意这样做的,因为我们希望在涉及安全性时检查当前请求(当前用户)。

因此,您的检查始终使用来自当前 HttpContext 的路由值,而不是基于节点 URL 创建的假上下文。要使用假上下文,您需要覆盖 OnAuthorization 并在那里使用 RequestContext

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var personId = filterContext.RequestContext.RouteData.Values["personId"];

        base.OnAuthorization(filterContext);
    }

这里真正的问题是(如果您使用保留的路由参数)您将整个站点的安全性建立在仅适用于 当前请求 的路由值上.当您的请求更改为不包含 personId 的内容时应该发生什么?节点都应该是不可见的吗?它们都应该可见吗?如果用户通过手动更改 URL 来更改路由值怎么办?这个安全模型有很多漏洞。

Important: Microsoft has said time and again the importance of not basing MVC security on the URL. The route values are just an abstraction of the URL, but don't really change the fact that they are based on the URL. It is virtually impossible to guarantee that an action method will only have a single route that can access it, which is why AuthorizeAttribute was created. AuthorizeAttribute secures the resource (action method) at its source so it can't be defeated by these alternate routes. Basing it on routes entirely defeats its purpose. In short, by including a route value in AuthorizeAttribute, you are opening up the possibility that your application can be hacked by an unintended alternate route to the action method. You are not simplifying security by basing AuthorizeAttribute on routes, you are making it more complex and nearly impossible to completely control over time.

最好将您的安全性基于 IPrincipalIIdentity 接口,它们是插入 MVC 的每种形式的安全性的一部分。在这种特殊情况下,AuthorizeAttribute 已经支持了一个用户 属性。没有添加 not user 的内置方法,但可以轻松地将此功能添加到您的自定义 AuthorizeAttribute.