About company Our development services Portfolio. Case studies Support Testimonials Contacts Brutka Ltd: web site development and custom software development

Information technology news archive


Использование преобразования протокола – рабочие заметки

Смена протокола и выборочное делегирование уже были подробно описаны в рубрике «Заметки о безопасности» — см. . Там я постарался дать полное представление о сущности расширений S4U протокола Kerberos, которые и делают возможным его использование. Более глубокие сведения об основах процесса смены протокола можно найти в главе 63 моей книги "The .NET Developer's Guide to Windows Security" («Безопасность ОС Windows. Руководство для разработчиков в среде .NET», на английском языке).
В настоящее время система Windows Server® 2003 устанавливается повсеместно, и ко мне приходят письма читателей, которые пытаются использовать смену протокола для создания безопасных шлюзов для своих интрасетей. Это прекрасная возможность, если необходимо использовать какой-либо альтернативный способ проверки подлинности в клиентской части и преимущества использования Kerberos в серверной части.
При использовании смены протокола шлюз (например веб-портал) может осуществлять проверку подлинности пользователя с помощью любой подходящей методики и выполнить вход с учетной записью Windows®, которая может быть обезличена и использоваться для доступа к ресурсам на серверах. Это означает возможность использования всех встроенных пользовательских функций безопасности Windows и в серверной части, включая группы, списки управления доступом (списки ACL), роли диспетчера авторизации (AzMan), роли COM+ и т.д.
Хотя в большинстве шлюзов и использовалось сопоставление учетным записями Windows, к примеру, в IIS реализовано сопоставление сертификатов учетным записям пользователей, однако в случае смены протокола нет необходимости хранить на шлюзе пароли для всех используемых ученых записей. Обычно для сеанса подключения необходим пароль, однако при использовании смены протокола можно сделать шлюз доверенным и установить сеанс подключения, не зная соответствующего пароля. В установленном сеансе подключения доступ в сеть будет ограничен: для этого сеанса будут предоставлены билеты Kerberos только для тех служб, которые перечислены в списке разрешений делегирования (A2D2) шлюза.
Сравним случаи атаки на шлюз, где хранятся пароли, и на шлюз, где используется смена протокола. Когда злоумышленник получает доступ к паролю пользователя, то он получает возможность выдавать себя за этого пользователя в любой точке сети по своему усмотрению как минимум до того момента, пока этот пользователь не изменит свой пароль; однако если злоумышленник получит доступ к доверенному шлюзу, где используется смена протокола, то паролей он там не найдет. Конечно, злоумышленник может войти в систему с учетными данными любого пользователя, чья учетная запись не имеет отметки «Конфиденциально и не допускает делегирования», однако он сможет использовать эти учетные данные только для доступа к службам, которые есть в списке A2D2. Масштаб ущерба будет ограничен в пространстве и во времени: атака может быть немедленно прекращена после ее обнаружения; в то же время если злоумышленник получит доступ к паролям пользователей, то у него будет большая свобода действий, и он сможет продолжать атаку из безопасного места.
Способ, с помощью которого шлюзу предоставляется доверие такого рода, состоит в предоставлении участнику системы безопасности или процессу шлюза прав на использование смены протокола с формированием списка конкретных служб, которым эти права можно делегировать. Это страница свойств «Делегирование» для учетной записи с именем MyWebIdentity — это учетная запись с низким уровнем привилегий, назначенным пулу приложений IIS 6.0, где выполняется пример веб-портала. Как можно заметить, учетная запись MyWebIdentity настроена на смену протокола, поскольку выбран параметр «Доверять этому пользователю делегирование указанных служб» и «Использовать любой протокол проверки подлинности». Обратите внимание, что для ограничения прав учетной записи MyWebIdentity использован список A2D2; таким образом, единственные билеты Kerberos, которые она сможет получить с помощью смены протокола, относятся только к файловой системе на компьютере, расположенном в домене с названием FileServer. CIFS означает Common Internet File System — это название файлового сервера Microsoft®.
Рис. 1. Настройка учетной записи на использование смены протокола (Щелкните изображение, чтобы увеличить его)
Кстати, вам будет интересно узнать, как мне удалось отобразить вкладку «Делегирование» для обычной учетной записи. Эта вкладка видна потому, что учетной записи назначено имя участника-службы (SPN), которое сообщает службе Active Directory® о том, что она предназначена для использования службой, а не пользователем. Вкладка "Делегирование" отображается только для тех участников безопасности, которым назначено как минимум одно имя участника-службы, поэтому эта вкладка обычно отображается только на страницах учетных записей компьютеров. Если требуется уточнить, что такое имя участника-службы (SPN), ознакомьтесь с документом "What is a Service Principal Name".
Дилемма привилегий
Несмотря на перспективы использования смены протокола, возможность входа пользователя в систему без пароля выглядит несколько пугающей. Технически говоря, для этого пользователю нет необходимости получения прав на смену протокола; любой, кто использует расширение Kerberos S4U2Self, может выполнить вход в качестве пользователя Windows Server 2003. Без предоставления прав на смену протокола обмен данными с другими серверами невозможен, однако как предотвратить повышение уровня привилегий обычного пользователя с помощью кода, который использует конструктор входа в систему S4U WindowsIdentity, описанный мной в предыдущих заметках о расширениях S4U Kerberos?
string admin = "administrator@mydomain.local";
using (WindowsIdentity id = new WindowsIdentity(admin)) // S4U logon
using (WindowsImpersonationContext ctx = id.Impersonate()) {
string SAM = @"c:\windows\repair\sam";
Console.WriteLine(File.ReadAllText(SAM));
}
В данном случае производится атака на базу данных учетных записей безопасности на локальном компьютере путем временного расширения привилегий до уровня администратора домена.
Понятно, что это было бы опасно, если бы это было возможно. Однако это невозможно. Несмотря на то, что злоумышленник сможет успешно выполнить несколько первых строк предыдущего кода, полученный при входе S4U маркер безопасности будет настолько ограниченным, что не сможет обеспечить поддержку олицетворения. Вызов файла File.ReadAllText будет неудачен, поскольку полученный для учетной записи администратора маркер может использоваться только для идентификации администратора, а не для его олицетворения.
Использовать конструктор входа в систему S4U в WindowsIdentity с целью получения маркера, который может быть успешно использован для олицетворения, может только пользователь с высоким уровнем привилегий. Вызываемая конструктором подсистема API Win32®, LsaLogonUser, проверяет, имеется ли у вызывающего процесса идентификатор SeTcbPrivilege, который является системным параметром по умолчанию. Это наиболее высокая привилегия в ОС Windows, так как она показывает, что пользователь является эффективной частью самой операционной системы или "доверенной вычислительной базы" (trusted computing base, TCB). Если пользователь уже признан доверенным на этом уровне, то у него нет ограничений в действиях, и система безопасности предоставит вход в систему S4U, который может олицетворен.
Мы подошли к тому месту, где у читателей начинают возникать сложности. Они хотят использовать смену протокола, но вскоре обнаруживают, что если процессы шлюза не запущены в качестве системных, все созданные подключения к системе бесполезны. Пользователи не могут олицетворить входы в систему для того, чтобы получить доступ к ресурсам сервера. Некоторые пошли дальше и повысили уровень шлюзов до системного и теперь переживают по этому поводу, другие же отказались от этого и принялись искать другие, более традиционные решения.

Расстановка привилегий высокого уровня
Эта дилемма может быть разрешена путем разложения процесса шлюза на две части. На самом деле привилегии доверенной вычислительной базы требуются только одной строке кода:
new WindowsIdentity(userPrincipalName)
Было бы безрассудным повышать уровень привилегий всего шлюза просто потому, что только одной этой строке необходим высокий уровень привилегий. Если есть процесс, который принимает данные от удаленных пользователей, выполняется постоянно и с высоким уровнем привилегий, то он создает опасную ситуацию. Решение состоит в том, чтобы удалить полностью эту одну строку кода из программы шлюза и перенести ее во вспомогательные процессы с высоким уровнем привилегий. Это несложно для опытных разработчиков систем Win32, однако если пользователь использует эту платформу или Win32 впервые, подобная задача может оказаться неразрешимой, поэтому далее в этой статье я хочу показать способ создания безопасной службы входа в систему, в которой размещается эта единственная строка чрезвычайно важного кода. Помимо этого, мы научимся многому другому, в том числе способу передачи маркеров между процессами с помощью среды Microsoft .NET Framework, способу расширения System.Security.AccessControl и использованию надстроек COM+ для размещения процессов с высоким уровнем привилегий.

Объекты ядра и дескрипторы
Каждый процесс ОС Windows имеет таблицу дескрипторов, ссылающуюся на такие объекты ядра ОС Windows, как файлы, семафоры, маркеры и т.д.. Дескрипторы Win32 - это целые числа, указывающие на эту таблицу и являющиеся значимыми только в процессе, который вызвал открытие данного дескриптора. Записав, например, значение дескриптора файла, в буфер обмена, нельзя ожидать, что их сможет прочитать другой процесс.
Если требуется передать открытый дескриптор другому процессу, следует использовать API DuplicateHandle Win32. Так как WindowsIdentity, которую использует служба входа в систему, включает один из этих дескрипторов, то ее сериализация для обмена данными не представляется приемлемым выходом. Для внедрения данных в целевую таблицу дескриптора процесса следует использовать дескриптор DuplicateHandle.
Схема действий такова: Служба шлюза будет производить вызов службы входа в систему с помощью некоторых методик обмена данными между процессами, которые довольно просты в обеспечении их безопасности. В качестве части этого вызова шлюз будет предоставлять два аргумента: имя пользователя, которому требуется выполнить вход в систему, и идентификатор процесса шлюза таким образом, чтобы служба входа в систему имела данные о том, куда направлять полученный дескриптор маркера. Служба входа в систему далее возвратит целое значение дескриптора, которое представляет собой индекс таблицы дескрипторов вызывающего процесса. Вызывающий процесс далее использует это значение как дескриптор Win32 и создает свое собственное значение WindowsIdentity для размещения этого дескриптора.
Ниже показан интерфейс .NET, который иллюстрирует подобное взаимодействие:
public interface ILogonService {
int LogonUserViaProtocolTransition(string upn, int callerPID);
}
Для того, чтобы облегчить внедрение этого интерфейса, рассмотрим следующие требования: Во-первых, процесс, который размещает эту службу входа, должен выполняться с привилегиями TCB, а наилучшим способом обеспечения подобных привилегий является запуск этой базы в качестве системной службы. Во-вторых, необходимо тщательно защитить интерфейс ILogonService таким образом, чтобы он мог использоваться только предназначенным шлюзом. В противном случае он будет действовать как механизм для повышения уровня привилегий, который позволит любому пользователю расширить полномочия путем входа в домен с правами учетной записи локального администратора. К счастью, существует технология, которая с легкостью разрешает обе эти проблемы и является встроенной в Windows Server 2003: старая добрая COM+.
Кто-то сказал, что COM+ умер? Это далеко не так. По моему мнению, использование COM+ является единственным способом при подобном разложении привилегий. Используя System.EnterpriseServices, можно написать компонент COM+ на наиболее удобном для пользователя управляемом языке. Далее можно полностью использовать модель размещения COM+ для того, чтобы автоматически размещать созданный компонент в службе, которая выполняется в качестве системной. Кроме того, пользователю не требуется писать единственную строку кода для этой службы. Не следует также забывать о ролевой безопасности в компоненте COM+, которая позволяет ограничить доступ к методу входа в систему созданного компонента таким образом, что использовать эту службу входа сможет использовать только тот участник безопасности, который уполномочен запускать шлюз.
После построения сборки LogonService мы производит ее внедрение в каталог COM+ путем запуска RegSvcs.exe, открыв средство администрирования «Службы компонентов» и найдя пакет сервера COM+ для службы входа LogonService. Для внедрения в службу, выполняющуюся в качестве системной, все, что необходимо, – это вывести на экран окно свойств этого пакета, перейти на вкладку «Активизация» и установить флажок «Запустить приложение как службу NT». После этого следует перейти на вкладку «Удостоверение», где стала доступна возможность выбора удостоверения "Локальная система". Выбрав этот вариант, настройку запуска службы входа в качестве системной службы можно считать законченной.

Объекты ядра и списки управления доступом
Еще один момент, о котором необходимо помнить, – это объекты ядра Windows, безопасность каждого из которых, включая отправляемые обратно маркеры, обеспечивается с помощью списков управления доступом. С технической точки зрения, поскольку предполагается отправка дубликата дескриптора обратно вызывающему процессу, список управления доступом не учитывается при использовании вызывающим процессом определенного дескриптора. Однако было бы надежнее настроить списки управления доступом маркера для гарантирования наличия прав субъекта безопасности вызывающего процесса, особенно с учетом того, что вызывающий процесс, вероятно, для управления дескриптором маркера будет использовать такие оболочки .NET, как WindowsIdentity. В результате может получиться так, что вызывающему процессу может быть отказано в использовании предоставленного ранее маркера.
К сожалению, .NET Framework пока не имеет класса, позволяющего управлять маркерами напрямую. Класс WindowsIdentity на сегодняшний день является наиболее близким по структуре к классу маркера. Однако я использовал эту возможность расширения классов в System.Security.AccessControl для поддержки маркерами чтения и записи списков управления доступом. Как я упоминал ранее, следует выразить признание группе разработчиков Windows, которые создали пространство имен AccessControl. Расширить NativeObjectSecurity для поддержки маркеров оказалось удивительно легко. Код может выглядеть довольно сложным, однако при более внимательном рассмотрении становится понятно, что он всего лишь выполняет настройки списков управления доступом для маркера. Самым интересным кодом является перечисление TokenRights; вся его оставшаяся часть является всего лишь шаблоном.
Реализация службы входа в систему показана на Рис. 3. Возможно, читатели сразу заметят атрибуты System.EnterpriseServices, которые подготавливают сборку и класс LogonService для размещения в каталоге COM+. Следует уделить особое внимание атрибутам безопасности, требующим проверки подлинности и конкретной роли вызывающих процессов для вызова службы входа в систему. (Я использовал роль с названием ProtocolTransitionUsers, а при развертывании службы входа в систему и ее настройке в каталоге COM+ убедился в том, что участник безопасности, с правами которого запущен мой шлюз, является членом этой роли.)
Кроме того, можно отметить вызовы CoImpersonateClient и CoRevertToSelf. Это прикладные пользовательские интерфейсы Win32, знакомые большинству программистов среды DCOM. Они позволяют определить, какой участник безопасности вызывает службу входа в систему, и получить идентификатор безопасности вызывающего элемента для переменной, которая позже используется для предоставления прав маркеру.
Остальная часть маркера предназначена для входа пользователя в систему с помощью конструктора входа в систему S4U в WindowsIdentity, с последующий отправкой маркера обратно вызывающему процессу. В связи с тем, что служба выполняется как системная, она будет иметь права копирования дескрипторов в любой процесс, который ей требуется по умолчанию. Как мы видим, так задумано, что системные службы обладают полным объемом разрешений для доступа ко всем объектам системы, в том числе ко всем процессам. Обратите внимание на вызов throwIfUserIsAdmin. Этот вспомогательный метод используется для проверки того, имеет ли полученный маркер права локального администратора. Это полезно для предотвращения использования службы входа в систему и получения привилегий администратора с помощью подконтрольного для злоумышленника шлюза, что сделает бесполезным все решение целиком.
И еще одно, что может заметить читатель в примере кода, - это несколько написанных мною нестандартных классов, производных от класса SafeHandle, с помощью которых проще управлять дескрипторами. В целом это бывает полезным при большом объеме работы P/Invoke. Это простой для понимания код, он приведен в файле SafeHandles.cs, прилагаемом для загрузки. Введите в строку поиска "Shawn Farkas SafeHandle", и на экран будут выведены записи членов группы разработки Microsoft .NET Framework, в которых есть сведения о том, как создать свой собственный класс SafeHandle classes(На английском языке).

Пример шлюза
Перед тем, как показать пример шлюза, следует подчеркнуть одну очень важную вещь: при использовании смены протокола следует соблюдать осторожность. Данная функция не содержит средств обеспечения подлинности входящих в систему пользователей. Если администратор домена включает смену протокола для идентификатора веб-приложения, он доверяет пользователю работу по проверке подлинности пользователей, которую обычно выполняет контроллер домена.
Теперь шлюз выполняет функции строжайшей проверки подлинности пользователей, входящих в систему, и только потом его особые привилегии используется для смены прокола и входа в систему соответствующий учетной записи Windows, представляющей определенного пользователя.
Поскольку целью данной статьи является описание смены протокола, то, в отличие от тысяч других способов проверки подлинности пользователей на внешнем сервере, в моем примере шлюз вообще не производит проверку подлинности пользователей. Он просто позволяет ввести имя пользователя и сетевой путь к файлу, попытка чтения которого производится с помощью интерфейса пользовательского входа S4U. К данному примеру можно добавить любую схему проверки подлинности клиента, чтобы начать использование смены протокола с такого процесса шлюза, который обладает низким уровнем привилегий. Повторю еще раз: не следует просто копировать пример шлюза в свое приложение, поскольку таким образом оно будет открыто

2007-03-26

 

More IT news, prices and information