3

У нас есть полностью работающая карта сайта со многими сотнями узлов, настроенных с атрибутами sitemap для действий. Эти узлы - это исправление безопасности, отлично работающее на основе требований. Все работает отлично и быстро.Безопасность Обрезка MVC сайтов поставщика Sitemap с атрибутом AuthAttribute на основе значений маршрута

Теперь у нас есть требование, чтобы определенные страницы были недоступны на основе значения маршрута. В основном скрываются ссылки на меню mvc на основе значения personId в маршруте. Используя код:

//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); 
    } 
} 

Это работает отлично с точки зрения предотвращения доступа. Однако, в отличие от остальной части нашего сайта, карта сайта не работает с этим. Если я посещаю человека, который ограничен первым, он скрывает узел для этого человека и всех остальных. Если я нахожусь с не скрытым человеком, то узел будет видимым для всех, но я получаю отказ в доступе для человека, если я попытаюсь посетить их узел.

Я предполагаю, что это связано с тем, что узел не имеет концепции обрезки на основе значений маршрута.

Любые идеи о том, как это можно реализовать. Мы пытаемся внедрить более гибкую модель безопасности.

ответ

3

Отключение здесь из-за различий между MVC и MvcSiteMapProvider использует AuthorizeAttribute.

В MVC AuthorizeAttribute просто проверяется в контексте текущего запроса. В текущем контексте содержится все, что необходимо для определения того, разрешено ли пользователю просматривать текущую страницу.

MvcSiteMapProvider проверяет каждый узел для каждого запроса. Поэтому мы не можем делать те же предположения, что текущий контекст является правильным для определения того, что узел доступен. Существует новый временный HttpContext, созданный для каждого узла (на основе созданного URL-адреса узла), а значения маршрута, используемые во время проверки, выводятся из этого контекста (а не из текущего контекста).

Эта подделка HttpContext не идеальна. Microsoft создала несколько избыточных свойств HttpContext, RequestContext и т. Д., Которые должны быть явно установлены или они будут по умолчанию для текущего контекста, а не все из них были установлены AuthorizeAttributeAclModule. Это было сделано намеренно в этом случае, потому что мы хотим, чтобы текущий запрос (текущий пользователь) был проверен, когда дело доходит до безопасности.

В результате ваш чек всегда использует значения маршрута от текущего HttpContext, а не поддельный контекст, созданный на основе URL-адреса узла. Чтобы использовать фальшивый контекст, вам нужно переопределить OnAuthorization и использовать там RequestContext.

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

     base.OnAuthorization(filterContext); 
    } 

Реальная проблема здесь в том, что (если вы используете сохранены параметры маршрута) вы основываете свою безопасность для всего сайта на стоимости маршрута, который применяется только к currrent запроса. Что должно произойти, когда ваш запрос изменится на то, что не включает personId? Должны ли все узлы быть невидимыми? Должны ли они все быть видимыми? Что, если пользователь изменит значение маршрута, изменив URL вручную? В этой модели безопасности много трещин.

Важно: Microsoft уже не раз говорил о важности не основывая безопасности MVC на URL. Значения маршрута - это просто абстракция URL-адреса, но на самом деле не изменяют тот факт, что они основаны на URL-адресе. Практически невозможно гарантировать, что метод действия будет иметь только один маршрут, который может получить к нему доступ, поэтому было создано AuthorizeAttribute. AuthorizeAttribute защищает ресурс (метод действия) в своем источнике, поэтому он не может быть побежден этими альтернативными маршрутами. Основываясь на маршрутах, полностью побеждает его цель. Короче говоря, включив значение маршрута в AuthorizeAttribute, вы открываете возможность того, что ваше приложение может быть взломан непреднамеренным альтернативным маршрутом к методу действий. Вы не упрощаете безопасность, основываясь на маршрутах AuthorizeAttribute, вы делаете его более сложным и практически невозможным полностью контролировать время.

Было бы лучше основывать свою безопасность на границах раздела IPrincipal и IIdentity, которые являются частью любой формы безопасности, которая вставляется в MVC. В этом конкретном случае существует свойство пользователя, которое уже поддерживается AuthorizeAttribute. Нет встроенного способа добавить not user, но эта функциональность может быть легко добавлена ​​к вашему пользовательскому AuthorizeAttribute.

+0

Спасибо. Мы размещаем атрибут только на узлах с идентификатором personId. Мы действительно обеспечиваем уровень данных, а также визуальную вещь - например, вы можете увидеть дисциплинарное замещение человека, если будете управлять ими, но нет, если вы этого не сделаете. Фактически мы ограничиваем доступ к некоторым людям для некоторых пользователей. Контекст не позволит вам получать данные, поскольку он обеспечивает уровень контекста на основе IClaimsPrincipal, и вы просто не получите никаких данных. Таким образом, страница будет бросать ошибку, не найденную в записи (не подходит для конечного пользователя). Просмотрите ваш всегда полезный совет. – GraemeMiller

+1

Это AuthorizeAttributeAclModule, который работает для вашего использования: https://gist.github.com/NightOwl888/30bef95ee9dd0b24c870. Я хотел бы сделать что-то подобное официально, но в этой версии отсутствуют некоторые фундаментальные части HttpContext (сеанс, профиль и т. Д.). Это потребует еще много работы, чтобы все это было в единый сплоченный контекст, который можно использовать для общего использования, но я считаю, что это можно сделать, связав эти зависимости с конструктором SiteMapHttpContext. – NightOwl888

+0

Очень ценим, что он работает. Просто нужно было обновить наш кеширующий декоратор, чтобы кэш-ключ добавил его personId, если он был частью значений маршрута. Считаете ли вы, что это лучший подход для ограничения видимости этих узлов? – GraemeMiller