Авторизация

122

До сих пор было показано только, как проверять, что пользователи являются действительно теми, за кого себя выдают, и как извлекать информацию об аутентифицированных идентичностях. Это предоставляет приложениям базовую возможность различать пользователей, но это лишь начальная точка. Чтобы создать действительно безопасное веб-приложение, понадобится выполнять их авторизацию в различных местах приложения.

Авторизация - это процесс определения того, имеет ли аутентифицированный пользователь достаточные привилегии на выполнение того или иного действия. Таким действием может быть запрос веб-страницы, доступ к ресурсу, управляемому операционной системой (такому как файл или база данных), либо выполнение специфичных для приложения задач (наподобие размещения заказа в системе управления заказами или назначения проекта в приложении управления проектами вроде Microsoft Project Server).

Некоторые из этих проверок Windows осуществляет автоматически, а другие можно кодировать декларативно, используя файл web.config. Но некоторые проверки придется выполнять непосредственно в коде с использованием объекта IPrincipal.

Авторизация URL

Самый простой способ установки прав доступа предусматривает их установку на индивидуальных веб-страницах, веб-службах и подкаталогах. В идеале платформа веб-приложений должна поддерживать специфичную к ресурсам авторизацию без необходимости изменения кода и перекомпиляции приложения. ASP.NET поддерживает это требование с помощью декларативных правил авторизации, которые можно определять в файле web.config.

Определяемые вами правила действуют через специальный модуль HTTP по имени UrlAuthorizationModule. Модуль просматривает эти правила и проверяет каждый запрос, гарантируя, что пользователю не будут доступны ресурсы, доступ к которым ограничен специальным образом.

Авторизация такого типа называется авторизацией URL, потому что принимает во внимание только две детали - контекст безопасности пользователя и URL ресурса, к которому пользователь пытается обратиться. Если доступ к странице запрещен и применяется аутентификация с помощью форм, то пользователь будет перенаправлен на страницу регистрации.

Правила авторизации

Правила авторизации определяются в элементе <authorization> файла web.config. Базовая структура выглядит следующим образом:

<configuration>
    <system.web>
      <authorization>
        <allow users="разделенный запятыми список пользователей"
            roles="разделенный запятыми список ролей"
            verbs="разделенный запятыми список типов запросов"/>
        <deny users="разделенный запятыми список пользователей"
            roles="разделенный запятыми список ролей"
            verbs="разделенный запятыми список типов запросов"/>
      </authorization>
    </system.web>
</configuration>

Другими словами, существуют два типа правил: разрешить (allow) и запретить (deny). Тех и других можно добавлять столько угодно. Каждое правило идентифицирует одного или более пользователей либо ролей (групп пользователей). Вдобавок можно использовать атрибут verbs, чтобы создавать правила, применимые только к специфичным типам HTTP-запросов (GET, POST, HEAD ИЛИ DEBUG).

В предыдущих статьях уже приводился простейший пример. Чтобы запретить доступ всем анонимным пользователям, можно определить правило <deny> вроде следующего:

<authorization>
	<deny users="?"/>
</authorization>

В данном случае вопросительный знак (?) - это шаблонный символ, представляющий всех пользователей с неизвестной идентичностью. Это правило почти всегда используется в сценариях аутентификации. Это связано с невозможностью запрета доступа другим, известным пользователям, если только сначала не заставить всех аутентифицировать себя.

Можно использовать дополнительный шаблонный символ - звездочку (*), которая представляет всех пользователей. Например, следующий раздел <authorization> открывает доступ аутентифицированным и анонимным пользователям:

<authorization>
	<allow users="*"/>
</authorization>

Такое правило требуется редко, потому что оно уже присутствует в файле machine.config. После того как среда ASP.NET применит все правила из файла web.config, она применяет правила из machine.config. В результате любому пользователю, кому явно закрыт доступ, автоматически его получает.

Теперь посмотрим, что произойдет, если в раздел <authorization> добавить более одного правила:

<authorization>
	<allow users="*"/>
    <deny users="?"/>
</authorization>

При оценке правил среда ASP.NET сканирует список сверху вниз. Как только она обнаружит применимое правило, поиск прекращается. Поэтому в предыдущем случае она определит, что правило <allow users="*" /> применимо к текущему запросу и не станет принимать во внимание вторую строку. В результате это правило разрешит доступ всем пользователям. Однако если две строки поменять местами, то доступ будет закрыт анонимным пользователям (согласно правилу в первой строке) и разрешен всем остальным (согласно правилу во второй строке).

Когда правила авторизации добавляются в файл web.config корневого каталога веб-приложения, они автоматически применяются ко всем веб-ресурсам, которые являются частью приложения. Если вход анонимным пользователям запрещен, ASP.NET проверит метод аутентификации. Если выбрана аутентификация с помощью форм, ASP.NET перенаправит пользователя на страницу регистрации.

В следующих разделах вы научитесь более тонкой настройке правил авторизации, чтобы точнее определять для них область действия.

Конфигурирование доступа для определенных пользователей

Правила <allow> и <deny> не обязательно требуют использования шаблонных символов звездочки или вопросительного знака. Вместо этого в них может быть конкретно указано имя пользователя или список имен пользователей, разделенный запятыми.

Например, следующее правило авторизации специально ограничивает доступ для трех пользователей. Эти пользователи не смогут обратиться к страницам, которые находятся в каталоге с файлом web.config, содержащим эти вхождения. Все остальные аутентифицированные пользователи обращаться к этим страницам смогут:

<authorization>
    <deny users="?"/>
    <deny users="Alex"/>
    <deny users="jeff"/>
    <deny users="bot18"/>
    <allow users="*"/>
</authorization>

Можно также определить список имен, разделенный запятыми, и запретить доступ сразу нескольким пользователям. Ниже показана версия, эквивалентная предыдущему примеру, в которой используются только два правила аутентификации:

<authorization>
    <deny users="?"/>
    <deny users="Alex, jeff, bot18"/>
    <allow users="*"/>
</authorization>

Обратите внимание, что в обоих случаях порядок следования этих трех пользователей в списке не важен. Однако важно, чтобы запрет на доступ этим пользователям предшествовал правилу <allow>.

Создавая безопасные приложения, часто лучше явно разрешить доступ определенным пользователям и группам, а затем запретить всем остальным (вместо запрета доступа определенным пользователям, как в предыдущих примерах). Ниже приведен пример правил авторизации, которые явно открывают доступ двум пользователям. Запросы всех прочих пользователей не будут удовлетворены, даже несмотря на то, что они аутентифицированы:

<authorization>
    <deny users="?"/>
    <allow users="Alex, jeff"/>
    <deny users="*"/>
</authorization>

Следует обратить внимание на одну деталь. Формат имен пользователей в этих примерах предполагает аутентификацию с помощью форм. При такой аутентификации имя пользователя назначается при вызове метода RedirectFromLoginPage(). В этой точке UrlAuthorizationModule также использует это имя и проверит его по списку правил авторизации.

Контроль доступа к определенным каталогам

Общепринятое проектное решение для приложения предусматривает размещение файлов, которые требуют аутентификации, в отдельном каталоге. Благодаря конфигурационным файлам ASP.NET, этот подход реализуется просто. Оставьте элемент <authorization в нормальном родительском каталоге пустым и добавьте файл web.config, который определяет более строгие установки в защищенном каталоге.

Вспомните, что когда вы добавляете файл web.config в подкаталог, он не должен содержать никаких других специфичных для приложения настроек. Фактически он должен содержать только информацию авторизации, как показано ниже:

<configuration>
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
</configuration>

Настройки дескриптора <authentication> в файле web.config подкаталога приложения изменять нельзя. Вместо этого все каталоги в приложении должны использовать одну и ту же систему аутентификации. Однако каждый каталог может иметь собственный набор правил авторизации.

При использовании правил авторизации в подкаталоге среда ASP.NET все равно читает правила авторизации из родительского каталога. Отличие в том, что правила из подкаталога применяются первыми. Это важно, потому что ASP.NET останавливается, как только находит соответствие правила авторизации. Рассмотрим пример, в котором корневой виртуальный каталог содержит одно правило:

<allow users="dan" /> 

а подкаталог - другое правило:

<deny users="dan" />

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

Более интересно то, что ASP.NET допускает неограниченную иерархию подкаталогов и правил авторизации. Например, вполне возможно иметь виртуальный каталог с правилами авторизации, подкаталог, определяющий дополнительные права, и еще один подкаталог внутри этого подкаталога, в котором определен свой набор правил. Проще всего понять процесс авторизации в этом случае - представить все правила в виде единого списка, начинающегося с каталога, в котором находится запрошенная страница. Если все эти правила обработаны и соответствие не найдено, ASP.NET начинает читать правила авторизации из родительского каталога, затем из каталога, родительского по отношению к этому, и т.д. - до тех пор, пока соответствие не будет найдено. Если никаких подходящих правил не найдено, ASP.NET в конечном итоге применяет правило <allow users="*"> из файла machine.config.

Контроль доступа к определенным файлам

Обычно установка прав доступа к файлам на уровне каталога - самый ясный и легкий подход. Однако существует возможность ограничить доступ к определенным файлам за счет добавления дескрипторов <location> в файл web.config.

Дескрипторы location размещаются вне главного дескриптора <system.web> и вложены непосредственно в базовый дескриптор <configuration>, как показано ниже:

<configuration>
  <system.web>
    <authorization>
      <allow users="*" />
    </authorization>
  </system.web>
  <location path="SecurePage.aspx">
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
  </location>
  <location path="AnotherSecurePage.aspx">
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
  </location>
</configuration>

В этом примере открывается доступ ко всем файлам приложения за исключением SecuredPage.aspx и AnotherSecuredPage.aspx, которые имеют правило авторизации, запрещающее анонимный доступ к ним.

Конфигурирование доступа для определенных ролей

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

Сама по себе аутентификация с помощью форм роли не поддерживает, но наряду с Membership API в ASP.NET доступен интерфейс API Roles, который представляет собой готовую к использованию реализацию поддержки и управления ролями для приложений. Кроме того, если вы не хотите использовать эту инфраструктуру, достаточно легко создать собственную, которая разделит пользователей на соответствующие группы на основе их удостоверений.

После определения для ролей можно создавать правила авторизации. Фактически эти правила выглядят точно так же, как показанные ранее правила, специфичные для пользователей. Например, следующие правила авторизации запрещают доступ анонимным пользователям, разрешая его двум конкретным пользователям (dan и alex) и двум группам (Manager и Supervisor). Доступ всем прочим пользователям запрещен:

<configuration>
    <system.web>
      <authorization>
        <deny users="?"/>
        <allow users="dan, alex" />
        <allow roles="Manager, Supervisor" />
      </authorization>
    </system.web>
</configuration>

Применение правил авторизации на основе ролей концептуально просто, но может оказаться сложным на практике. Дело в том, что при использовании ролей правила авторизации могут перекрываться.

Например, рассмотрим, что произойдет, если вы разрешите доступ группе, которая содержит определенного пользователя, а затем явно закроете доступ этому пользователю. Или наоборот - разрешив доступ пользователю по имени, вы закроете доступ группе, в которую он входит. В этих сценариях можно ожидать, что более тонко детализированные правила (касающиеся пользователя) получат приоритет по отношению к более общим правилам (касающимся групп). Или же вы можете ожидать, что более ограничивающие правила всегда будет иметь более высокий приоритет, как это принято в Windows. Однако ни один из этих подходов не используется ASP.NET. Вместо этого ASP.NET просто применяет первое подходящее правило. В результате решающее значение имеет порядок определения правил.

Рассмотрим пример:

<authorization>
	<deny users="?"/>
	<allow users="alex" />
	<deny roles="Guest" />
    <allow roles="Manager" />
    <deny users="dan" />
	<allow roles="Supervisor" />
    <deny users="*"/>
</authorization>

Ниже описано, как ASP.NET разбирает эти правила:

Имейте в виду, что все эти перекрывающиеся правила могут также охватывать множество каталогов. Например, подкаталог может быть закрыт для пользователя, в то время как родительский каталог может быть открыт для пользователя в его группе. В этом примере при доступе к файлам подкаталога первым применяется правило, специфичное для пользователя.

Файловая авторизация

Авторизация на основе URL - один из краеугольных камней авторизации ASP.NET. Однако в ASP.NET также используется другой тип авторизации, который часто пропускается или игнорируется многими разработчиками. Это авторизация на основе файлов, реализуемая модулем FileAuthorizationModule. Авторизация на основе файлов работает, только в случае применения Windows-аутентификации. Если же используется специальная аутентификация или аутентификация с помощью форм, файловая авторизация не применяется.

Чтобы понять суть файловой авторизации, необходимо разобраться, как операционная система Windows обеспечивает безопасность файловой системы. В случае файловой системы NTFS можно установить списки ACL (access control list - список контроля доступа), указывающие идентичность пользователей и ролей, которым открыт или запрещен доступ к индивидуальным файлам. Модуль FileAuthorizationModule просто проверяет права доступа к запрошенному файлу, определенные Windows.

Например, если запрашивается веб-страница, FileAuthorizationModule проверяет, имеет ли текущий аутентифицированный IIS пользователь права доступа к соответствующему файлу .aspx. Если не имеет, то код страницы не выполняется и пользователь получает сообщение о запрете доступа.

Новые пользователи ASP.NET часто удивляются, почему файловая авторизация должна быть реализована отдельным модулем, и почему бы ни положиться в этом на операционную систему?

Чтобы понять необходимость в модуле FileAuthorizationModule, необходимо вспомнить, как ASP.NET выполняет код. Если не включено заимствование прав, ASP.NET выполняется от имени фиксированного пользовательской учетной записи, такой как ASPNET. Операционная система Windows будет проверять, имеет ли учетная запись ASPNET права, необходимые для доступа к файлу .aspx, но она не выполнит ту же проверку для пользователя, аутентифицированного IIS. Модуль FileAuthorizationModule заполняет этот пробел. Он осуществляет проверку авторизации с учетом контекста безопасности текущего пользователя. В результате системный администратор может устанавливать права доступа к файлам или папкам и контролировать доступ к частям приложения ASPNET. Обычно проще и удобнее использовать правила авторизации в файле web.config. Однако если необходимо воспользоваться преимуществами существующих привилегий Windows в локальной или корпоративной сети, то это можно сделать.

Пройди тесты
Лучший чат для C# программистов