Защита в DCOM/COM+ Часть 2

Права активации

Под Windows 9x COM-сервер не запускается автоматически по требованию клиента. В ОС этой линейки приходится запускать COM-серверы вручную. Ввиду практически полной незащищенности, плохой устойчивости к сбоям и недостаточной функциональности реализуемых сервисов, Windows 9x вообще лучше не использовать в качестве платформы для серверных приложений. В отличие от Windows 9x, ОС линейки NT прекрасно подходят для запуска COM-серверов. Так, эти ОС поддерживают автоматический запуск приложений удаленными клиентами. Например, если клиент вызвал функцию, активирующую COM-объект (скажем, CoCreateInstance), реализованный в некотором сервере, COM SCM проверяет, зарегистрирована ли для этого объекта в системе фабрика класса. Если не зарегистрирована, то COM SCM находит (через реестр) исполняемый модуль этого сервера, запускает его на выполнение и ждет некоторое время регистрации необходимой фабрики классов.

В ходе этого процесса COM SCM проверяет, имеет ли пользователь, осуществляющий запрос на создание объекта, право на запуск сервера. Сведения о тех, кому разрешено/запрещено запускать сервер, называются «правами активации» (или «launch permissions»). Они хранятся в именованном значении LaunchPermission, находящемся в ветке HKEY_CLASSES_ROOT\AppID\{AppID приложения} реестра. LaunchPermission имеет тип REG_BINARY и хранит сериализованный вид дескриптора безопасности. Настроить права активации можно из утилиты dcomcnfg. Для этого в dcomcnfg.exe нужно найти необходимое приложение, открыть его свойства, перейти на закладку «Security», выбрать пункт «Use custom launch permissions» и нажать на соответствующую (их там много) кнопку «Edit» (см. рисунок 5).

Защита в службах Windows и DCOM

Рисунок 5. Настройка прав активации (dcomcnfg).

Дескриптор безопасности определяет учетные записи, которым разрешено или запрещено запускать сервер. В этот дескриптор обязательно должна входить учетная запись SYSTEM. Современные версии утилит dcomcnfg и OLEViewer добавляют эту запись автоматически. Однако старые версии не делали этого.

Если права активации не были явно заданы, будут действовать права доступа «по умолчанию». Они распространяются на всю машину и задаются в именованном значении DefaultLaunchPermission ветки реестра HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Ole. Это значение, так же как и LaunchPermission (описанное выше), содержит дескриптор защиты.

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

Права доступа

Каждое COM-приложение (и клиентское, и серверное) может определить настройки защиты по умолчанию. Такие настройки задают провайдеров безопасности и минимальные значения для параметров защиты. Умолчания задаются в момент, когда внутри приложения первый раз вызывается CoInitializeSecurity. Это может происходить неявно (когда сервер, не вызывая CoInitializeSecurity, пытается создать первый COM-объект, или в COM+, где это делает рантайм-подсистема) и явно (вручную) при старте приложения/сервиса.

Очень распространенной ошибкой является попытка вызвать эту функцию после того, как она уже была вызвана. Эту ошибку особенно трудно осознать, если CoInitializeSecurity в первый раз была вызвана неявно. Так, не стоит пытаться вызвать эту функцию из COM-сервера, расположенного в DLL, даже если DLL зарегистрирована в COM+-приложении, ибо к моменту создания пользовательского объекта данная функция точно уже вызвана самим COM.

Из книг по COM многие знают, что права доступа к объектам сервера и другая информация о защите хранятся в реестре и обычно задаются с помощью утилиты dcomcnfg (закладка Security). Реально же атрибуты защиты (кроме прав на активацию) задаются функцией CoInitializeSecurity. Для чтения из реестра настроек защиты нужно вызвать CoInitializeSecurity с определенными значениями параметров.

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

Еще одну проблему, как ни странно, вносит библиотека ATL (призванная упростить создание COM-серверов и сервисов). Происходит это из-за того, что визард генерирует следующий код:

// This provides a NULL DACL which will allow access to everyone.
CSecurityDescriptor sd;
sd.InitializeFromThreadToken();
hr = CoInitializeSecurity(sd, -1, NULL, NULL,
 RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);

Этот код говорит COM, что к объекту может иметь доступ кто угодно. При этом настройки безопасности доступа в реестре не влияют на реальную политику безопасности. Есть и еще один фактор, который может повлиять на безопасность доступа – это атрибуты защиты, заданные для исполняемого файла сервера. Так что если поместить exe-файл COM-приложения в папку, к которой запрещен доступ некоторой учетной записи, при обращении к приложению обладатель этой учетной записи столкнется с сообщением «access denied». При этом можно долго задавать «custom access permissions» в DCOMCNFG и не понимать, почему сервер не работает.

Чтобы заставить ATL-сервер работать так, как написано в большинстве книг по COM, т.е. чтобы правами доступа можно было управлять через dcomcnfg, нужно изменить инициализацию защиты так, чтобы настройки считывались из ветки реестра, соответствующей AppID. Для этого нужно заменить приведенные выше строки кода на следующие:

struct __declspec(uuid("8030105E-9B2A-4758-9AF9-12CCC4507468")) CAppID;
GUID gAppID = __uuidof(CAppID);
hr = CoInitializeSecurity(&gAppID, -1, NULL, NULL, NULL, NULL, NULL, 
 EOAC_APPID, NULL);

Здесь 8030105E-9B2A-4758-9AF9-12CCC4507468 – AppID. Это значение генерирует ATL-визард, его можно найти в коде функции _tWinMain и RegisterServer.

Можно также передать NULL вместо AppID. При этом реальный AppID будет искаться по имени исполняемого модуля. Но такой подход менее предпочтителен, поскольку в случае использования длинных имен файлов или пути к исполняемому файлу могут возникнуть проблемы.

Иногда защита не только не нужна, но и вредна, так как на нее приходится тратить время и нервы. Особенно это справедливо по отношению к предоставляющим callback-интерфейсы клиентским приложениям, запускаемым под управлением Windows 9x. В таком случае имеет смысл отключить защиту вообще. Для этого нужно вызвать CoInitializeSecurity следующим образом:

hr = CoInitializeSecurity(
 NULL, -1, NULL, NULL,
 RPC_C_AUTHN_LEVEL_NONE, 
 RPC_C_IMP_LEVEL_IDENTIFY, 
 NULL, EOAC_NONE, NULL
);
...

Никакой защиты... но и никакой с ней мороки! Более детально этот вопрос разбирается в конце статьи.

Чтобы понять, как все это работает, рассмотрим поподробнее функцию CoInitializeSecurity.

CoInitializeSecurity

Как уже говорилось ранее, эта функция задает значения по умолчанию для процесса, в котором она вызывается. Вот ее описание:

HRESULT CoInitializeSecurity(

 // реально указатель на void-значение зависит
 // от значения параметра dwCapabilities
 PSECURITY_DESCRIPTOR pVoid, 

 // Количество элементов в asAuthSvc. Если задать -1,
 // COM будет сам выбирать сервис аутентификации.
 LONG cAuthSvc, 
 
 // Массив сервисов аутентификации, которые приложение 
 // хочет использовать при приеме вызовов. 
 SOLE_AUTHENTICATION_SERVICE * asAuthSvc, 

 void * pReserved1, //Зарезервирован. Должен содержать NULL

 // Выбираемый по умолчанию (для proxy) уровень аутентификации.
 DWORD dwAuthnLevel,

 // Выбираемый по умолчанию (для proxy) уровень имперсонации.
 DWORD dwImpLevel,

 // NULL в NT 4. Под W2k может содержать информацию для 
 // сервисов аутентификации.
 SOLE_AUTHENTICATION_LIST * pAuthList,

 // Определяет, как будет производиться настройка прав доступа.
 DWORD dwCapabilities,

 void * pReserved3 //Зарезервирован. Должен содержать NULL
);

Первый параметр применяется для задания списка учетных записей (ACL), которым будет разрешен доступ к объектам данного сервера. Для клиента этот список значения не имеет. Впрочем, не надо забывать, что клиент и сервер могут легко поменяться местами (например, если сервер реализует события, а клиент подключается к ним).

Данный список можно инициализировать несколькими способами:

через AppID. Пожалуй, это лучший способ инициализации, т.к. он позволяет администратору настраивать атрибуты защиты с помощью dcomcnfg или OLEViewer.

через интерфейс IAccessControl. Данный способ инициализации может пригодиться, если в качестве сервера выступает Windows 9x или Unix-машина. Последнее хотя и маловероятно, но возможно – CA перенесла COM на большое количество Unix-совместимых платформ. Для серверов, запускаемых под управлением NT, применение данного способа инициализации списка защиты нежелательно.

и традиционный для Windows NT способ, через заполнение структуры SECURITY_DESCRIPTOR

То, как будет производиться инициализация, определяет восьмой по счету параметр dwCapabilities. Вот его возможные значения:

  • EOAC_NONE означает, что никакие флаги не заданы. Инициализация защиты производится с помощью структуры SECURITY_DESCRIPTOR. Указатель на структуру SECURITY_DESCRIPTOR должен быть передан в качестве первого параметра.
  • EOAC_ACCESS_CONTROL – инициализация защиты производится с помощью интерфейса IAccessControl. Указатель на интерфейс должен быть передан в качестве первого параметра функции. DCOM впоследствии вызовет этот интерфейс для определения того, кто может взаимодействовать с сервером. DCOM увеличивает счетчик ссылок этого интерфейса и таким образом «держит» объект, реализующий интерфейс, до вызова функции CoUninitialize.
  • EOAC_APPID – этот флаг говорит DCOM-у, что информацию о защите нужно искать в AppID приложения. При этом в качестве первого параметра функции необходимо передать указатель на AppID или NULL. В случае, если передан AppID, COM сразу обратится к необходимой ветке реестра. Если же в первом параметре передан NULL, то COM будет искать в ключе AppID реестра подключ, соответствующий имени исполняемого файла. Если таковой будет найден, COM прочтет значение AppID из одноименного значения реестра. Полученное значение будет использовано так же, как если бы указатель на него был передан в качестве первого параметра функции.

Второй параметр этой функции, cAuthSvc, позволяет задать количество элементов, содержащихся в списке сервисов аутентификации, задаваемом третьим параметром (asAuthSvc). Если передать в cAuthSvc ноль, не одного сервиса аутентификации не будет зарегистрировано и сервер не сможет обрабатывать защищенных вызовов. Если передать в cAuthSvc -1, COM будет самостоятельно выбирать сервисы аутентификации для регистрации.

Третий параметр (asAuthSvc) позволяет задать список сервисов, которые могут применяться при вызове методов сервера. Если значение параметра cAuthSvc равно 0 или -1, asAuthSvc должен содержать NULL.

Параметр dwAuthnLevel задает уровень аутентификации, используемый приложением.

Для сервера этот параметр задает нижнюю границу. Все вызовы от proxy, которым задан более низкий уровень аутентификации, будут отвергнуты COM.

При вызове в клиентском процессе данный параметр задает уровень аутентификации, который будет использоваться по умолчанию. COM использует данное значение в алгоритме вычисления атрибутов безопасности (о котором речь пойдет ниже) при расчете уровня аутентификации для proxy.

Уровень аутентификации можно переопределить для конкретной proxy/stub (с помощью IClientSecurity::SetBlanket, о чем пойдет речь ниже). Это позволяет задать с помощью функции CoInitializeSecurity общий (минимальный) уровень аутентификации, а в случае необходимости изменить данный параметр для конкретной proxy/ stub.

dwAuthnLevel может принимать следующие значения:

  • RPC_C_AUTHN_LEVEL_DEFAULT – говорит DCOM выбрать уровень аутентификации, используя нормальный алгоритм вычисления атрибутов безопасности (см. Security Blanket Negotiation ниже). Такое поведение имеет место в W2k и более поздних версиях Windows. В NT4 это значение по умолчанию равно RPC_C_AUTHN_LEVEL_CONNECT.
  • RPC_C_AUTHN_LEVEL_NONE – не производить аутентификации.
  • RPC_C_AUTHN_LEVEL_CONNECT – аутентифицировать клиента только при подключении к серверу. При использовании транспортных протоколов, основанных на передаче дейтаграмм (например, UDP) всегда используется RPC_AUTHN_LEVEL_PKT.
  • RPC_C_AUTHN_LEVEL_CALL – производить аутентификацию только в начале каждого удаленного вызова процедуры, при получении запроса сервером.
  • RPC_C_AUTHN_LEVEL_PKT – производить аутентификацию при передаче каждого пакета. Это гарантирует, что полученные данные пришли от ожидаемого клиента.
  • RPC_C_AUTHN_LEVEL_PKT_INTEGRITY – то же, что и RPC_C_AUTHN_LEVEL_PKT, но в пакет помещается цифровая подпись сообщения. Это гарантирует, что данные, которыми обмениваются клиент и сервер, не были изменены.
  • RPC_C_AUTHN_LEVEL_PKT_PRIVACY – то же, что и RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, но пакет шифруется перед каждым удаленным вызовом.
ПРЕДУПРЕЖДЕНИЕ

Хотя Windows 95 может производить вызовы на любом уровне аутентификации, принимать вызовы она может только с уровнем RPC_C_AUTHN_LEVEL_NONE или RPC_C_AUTHN_LEVEL_CONNECT

dwImpLevel – используется только для приложений которые являются клиентами COM-серверов. Этот параметр определяет, каким образом сервер может воспользоваться токеном клиента. Допустимые значения для этого параметра следующие:

  • RPC_C_IMP_LEVEL_DEFAULT – говорит DCOM выбрать уровень аутентификации, используя нормальный алгоритм вычисления атрибутов безопасности (см. Security Blanket Negotiation ниже). Такое поведение имеет место в W2k и более поздних версиях Windows.
  • RPC_C_IMP_LEVEL_ANONYMOUS – (не поддерживается) Клиент анонимен для сервера. Серверный процесс может имперсонировать клиента, но токен имперсонации не будет содержать никакой информации и не может использоваться ни для чего.
  • RPC_C_IMP_LEVEL_IDENTIFY – сервер может имперсонировать клиента (задавать токен клиента текущему потоку) для проверок ACL, но не может обращаться к защищенным объектам системы от имени клиента. Обратите внимание, сервер может производить проверки прав клиента, но не все функции API могут нормально работать в режиме IDENTIFY. Это связано с тем, что проверка происходит в имперсонированном потоке, у которого просто нет прав на осуществление таких операций. Так, например, функция GetUserName возвратит ошибку. О том, как считывать информацию о клиенте в подобных случаях, будет сказано ниже при описании примера ComSec.
  • RPC_C_IMP_LEVEL_IMPERSONATE – сервер может имперсонировать клиента и осуществлять операции над локальными ресурсами (например, файлами или реестром). При этом уровне имперсонации сервер не может производить удаленные вызовы от лица клиента. Служба аутентификации SChannel поддерживает только этот уровень имперсонации.
  • RPC_C_IMP_LEVEL_DELEGATE – то же, что и предыдущие но вызов может производить удаленные вызовы и обращаться к сетевым ресурсам от имени клиента. Процесс сервера может также вызывать другие серверы от имени клиента с помощью маскировки (Cloaking). Поддерживается в W2k и более поздних версиях ОС.

pAuthList – под W2k этот параметр является указателем на SOLE_AUTHENTICATION_LIST, массив структур SOLE_AUTHENTICATION_INFO. Этот список содержит информацию для каждой службы аутентификации, которую может использовать клиент при вызове сервера. Этот параметр используется, только когда в клиентском приложении вызывается CoInitializeSecurity. В NT4 pAuthList должен иметь значение NULL.

dwCapabilities – этот параметр задает дополнительные характеристики (как для клиента, так и для сервера). Характеристики задаются с помощью флагов, объявленных в перечислении EOLE_AUTHENTICATION_CAPABILITIES. О некоторых из них уже упоминалось при описании первого параметра этой функции. Ниже приведено описание остальных флагов:

  • EOAC_NO_CUSTOM_MARSHAL – поддерживается только в W2k. Этот флаг предотвращает использование объектов, использующих ручной маршалинг. Он может быть использован для борьбы с хакерскими атаками. Но не стоит им злоупотреблять, так как при этом могут отказаться работать очень многие объекты.
  • EOAC_SECURE_REFS – заставляет COM засекретить работу по подсчету ссылок, чтобы злоумышленники не могли влезть в этот процесс. Включать этот параметр в большинстве случаев не надо, так как это может привести к замедлению работы приложения.
  • EOAC_NONE – Указывает что никаких флагов не задано.
  • EOAC_STATIC_CLOAKING – задает статическую маскировку. Если этот флаг установлен, DCOM использует токен потока (если таковой имеется) при установлении личности клиента. Личность клиента определяется при первом вызове любой proxy (если не вызывается SetBlanket), и у proxy каждый раз вызывается CoSetProxyBlanket. Этот флаг может быть установлен только клиентами и используется в W2k и более поздних версиях ОС.
  • EOAC_DYNAMIC_CLOAKING – задает динамическую маскировку. Если этот флаг установлен, DCOM при установлении личности клиента использует токен потока (если таковой имеется). При каждом вызове proxy токен проверяется на предмет подлинности клиента (в этом случае происходят потери производительности), и клиент аутентифицируется заново только при необходимости. Динамическая маскировка может быть задана только клиентом и используется в W2k и более поздних версиях ОС.
  • EOAC_ANY_AUTHORITY – говорит DCOM поверить сертификату сервера SChannel, даже если к сертификату верхнего уровня нет никакого доверия. Это значит, что если поступает вызов, использующий SChannel, DCOM разрешит вызов, даже если top level certificate authority не установлен на машине. При установке этого флага нужно быть осторожным, поскольку наличие непроверяемого root'а серьезно подрывает безопасность сессии. Приложения должны использовать этот флаг, только если производится ручная проверка серверного сертификата. Этот флаг может быть установлен только клиентами и используется в W2k и более поздних версиях ОС.
  • EOAC_MAKE_FULLSIC – заставляет DCOM извлечь из сертификатов имена принципалов SChannel в формате fullsic. Используется в W2k и более поздних версиях ОС.
  • EOAC_REQUIRE_FULLSIC – заставляет DCOM отказывать в вызовах CoSetProxyBlanket, если имена принципалов SChannel указаны в любом формате, отличном от fullsic. Этот флаг предназначен только для клиентов.
  • EOAC_DISABLE_AAA – приводит к неудаче с возвратом E_ACCESSDENIED любой активации, если серверный процесс запускается под учетной записью клиента. Это значение, задаваемое только в клиентском вызове CoInitializeSecurity, позволяет приложению, работающему под привилегированной учетной записью (например, LocalSystem) предотвратить использование своих прав для запуска непроверенных компонентов. Используется в W2k и более поздних версиях ОС.

Функция CoInitializeSecurity не задает конкретных параметров безопасности. Она только указывает COM, какие значения максимально (или минимально) допустимы. Конкретные значения, назначаемые новой proxy вычисляются COM-ом в процессе «Security Blanket Negotiation».

Алгоритм вычисления атрибутов безопасности для proxy (Security Blanket Negotiation)

Security blanket – это настройки безопасности, применяемые к proxy. Это понятие включает следующие значения:

  • Сервис аутентификации
  • Сервис авторизации
  • Имя принципала (только для сервера)
  • Уровень аутентификации
  • Уровень имперсонации (только для клиента)
  • Идентичность клиента (только для клиента)
  • Дополнительные параметры имперсонации (только для клиента)
  • ACL, содержащий список учетных записей, которым разрешен доступ к объекту (только для сервера).

Как не трудно догадаться, эти значения соответствуют параметрам функции CoInitializeSecurity.

Security blanket negotiation – это алгоритм, который применяется COM для вычисления конкретных значений атрибутов защиты, присваиваемых новой proxy. Этот алгоритм сравнивает Security blanket сервера и клиента, и выбирает подходящие обеим сторонам атрибуты защиты (которые как раз и задаются при вызове CoInitializeSecurity).

Некоторые параметры функции CoInitializeSecurity применяются, если приложение является сервером, а некоторые – если оно является клиентом.

Когда CoInitializeSecurity вызывается для сервера, учитываются: ACL, список сервисов аутентификации/авторизации, принципал и уровень аутентификации.

Для клиента используются: уровень аутентификации, уровень имперсонации, информация о пользователе, подтверждающая его личность, и дополнительные параметры (задающиеся в параметре dwCapabilities). При этом клиент определяет, какие установки защиты он хочет применять при вызове удаленных методов.

Когда COM создает новую proxy, он считывает настройки сервера и пожелания клиента, и создает установки для этой proxy. При этом COM подбирает сервис аутентификации, который работает и на клиенте, и на сервере. COM выбирает высший уровень аутентификации из заданных для клиента и сервера. Сервис авторизации и имя принципала подбираются так, чтобы они могли использоваться с выбранным сервисом аутентификации. Уровень имперсонации и соответствующие атрибуты берутся из настроек клиента. Это позволяет клиенту обезопасить себя, например, запретив имперсонацию и разрешив только получение информации о своей учетной записи.

После создания proxy её настройки защиты можно изменить с помощью IClientSecurity::SetBlanket. Значение, задаваемое функцией SetBlanket, не вычисляется, как описывалось ранее, а просто применяется к proxy. Однако если функции SetBlanket передается значение ХХХ_DEFAULT, то реальное значение вычисляется по описанному выше алгоритму.

Защита в службах Windows и DCOM

Dcomcnfg.exe

Как уже было сказано выше, с помощью CoInitializeSecurity можно заставить DCOM считывать настройки безопасности из реестра. Задать эти настройки можно с помощью утилиты dcomcnfg. Эта утилита позволяет задавать настройки защиты для конкретного приложения, а также настройки защиты, используемые по умолчанию.

Проще всего запустить dcomcnfg из командной строки, так как по умолчанию эта утилита не имеет ярлыка.

Защита в службах Windows и DCOM

Рисунок 7. Утилита dcomcnfg.

Dcomcnfg –небольшое диалоговое приложение с четырьмя закладками-страницами (похожий диалог можно увидеть, если открыть свойства локального компьютера в консоли Component Services):

Applications – содержит список COM-приложений. Выбрав одно из них, можно открыть диалог его настройки (кнопка Properties).

Default Properties – позволяет задать значения по умолчанию для уровней аутентификации и имперсонации. На этой странице можно также включить или выключить DCOM для текущей машины. Если DCOM выключен, работа с COM-объектами по сети невозможна. Значения этого переключателя можно найти в реестре по адресу HKEY_LOCAL_MACHINE\Software\Microsoft\OLE. На этой же странице есть еще одна опция, которая относится к защите. Она называется "Provide additional security for reference tracking". Эта опция заставляет COM защищать вызовы методов интерфейса IUnknown, отвечающие за подсчет ссылок. Это может предотвратить несанкционированное уничтожение объекта, например, вследствие вмешательства злоумышленников. (рисунок 7)

Default Security – На этой странице можно задать значения по умолчанию для прав доступа и прав активации. Эти значения тоже хранятся в ключе HKEY_LOCAL_MACHINE\Software\Microsoft\OLE, в значениях DefaultAccessPermission и DefaultLaunchPermission, соответственно. Их содержимое – не что иное, как сериализованный дескриптор защиты. Эти настройки будут использоваться обычными DCOM-приложениями, если настройки для этих приложений не заданы явно. При задании прав нужно помнить, что список тех, кому разрешен доступ, обязательно должен содержать учетную запись SYSTEM! Иначе вы будете получать загадочные сообщения об ошибке (например, "не хватает памяти" или "не могу загрузить user.dll"). Новые утилиты (dcomcnfg и OLEViewer) автоматически добавляют ее, но старые этого не делали, так что будьте осторожны. На COM+-приложения эти настройки не распространяются.

На этой закладке есть еще одна кнопка - Default Configuration Permissions. Она позволяет настроить ACL разрешений/запрещений для ключа HKEY_CLASSES_ROOT. В этот ключ помещается информация о COM-объектах, регистрируемых в системе. Если запретить кому-нибудь доступ на запись в этот ключ реестра, этот кто-то не сможет устанавливать в систему COM-приложения. Будьте осторожны, так как HKEY_CLASSES_ROOT может быть довольно большим и изменение прав доступа к нему может занять довольно много времени.

Default Protocols – эта закладка позволяет настроить список и приоритет использования для сетевых протоколов, используемых DCOM. Ее рассмотрение выходит за рамки этой статьи.

Для задания прав доступа к ключевым (с точки зрения COM) веткам реестра можно использовать regedt32 (regedit в Windows XP). Это позволит избежать лишних проблем с излишне продвинутыми пользователями или, наоборот, делегировать часть прав по администрированию обладателям менее привилегированных учетных записей.

Настройка свойств отдельного DCOM-приложения производится в отдельном диалоговом окне, которое (как уже говорилось выше) можно вызвать на страницы Applications. Все установки, которые можно задать в этом диалоге, хранятся в ключе реестра HKEY_CLASSES_ROOT\AppID\{AppID приложения}. На рисунке 8 показано содержимое этого ключа для COM-сервера SampleServerWithEvents (из второго теста).

Защита в службах Windows и DCOM

Рисунок 8. Настройки защиты COM-объекта (вид из реестра).

Ниже кратко описаны страницы этого диалога, имеющие отношение к делу:

General – позволяет задать минимальный уровень аутентификации и получить кое-какую (малоинтересную) информацию. К сожалению, из dcomcnfg нельзя задать минимальный уровень имперсонации (как это можно сделать из диалога настройки COM+-приложения). Если нужно, можете сделать это программно (с помощью функции CoInitializeSecurity).

Location – к защите прямого отношения не имеет. Позволяет указать, где будет запускаться сервер (на удаленном сервере или на данной машине). Обычно используется для указания компьютера- сервера. Данная установка не действует, если объект создается с помощью CoCreateInstanceEx (CreateObject в VB6), и имя сервера задано явно.

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

Identity – эта страница позволяет указать, под какой учетной записью и в какой Windows-станции будет запускаться DCOM-приложение. Dcomcnfg помещает настройки, сделанные на этой странице, в значение реестра RunAs. Вот возможные значения этого параметра:

  • The Interactive User – приложение будет запускаться под учетной записью вошедшего в систему интерактивного пользователя. При этом приложение будет запускаться в WinSta0 (см. выше), что позволит ему интерактивно взаимодействовать с пользователем. «Интерактивно взаимодействовать» подразумевает, что пользователь увидит все видимые окна, открываемые приложением (например, диалоги ASSERT), и, если у него есть соответствующие привилегии, сможет отлаживать приложение. Данный вариант настройки прекрасно подходит для отладки или поиска проблем. Для реальной работы этот режим годится плохо, так как приложение просто не запустится, если в системе нет интерактивного пользователя. К тому же, если в систему зайдет пользователь с недостаточными правами, работоспособность приложения может оказаться под угрозой. Естественно, когда интерактивный пользователь выходит из системы, все DCOM-приложения с данной настройкой принудительно закрываются. При выборе этого варианта загрузки в поле реестра RunAs заносится значение «Interactive User». Этот вариант запуска недоступен, если сервер зарегистрирован как сервис.
  • The Launching User – приложение будет запускаться под учетной записью запускающего пользователя (обычно удаленного). Описать данный параметр стоит хотя бы для того, чтобы отговорить вас от его применения. Это особенно актуально потому, что этот параметр по нерадивости программистов из Microsoft применяется для DCOM-приложений по умолчанию (справедливости ради нужно заметить, что в COM+ он вообще отсутствует). Чем же так плох этот параметр? Дело в том, что при этой настройке COM SCM создает отдельный серверный процесс для каждой учетной записи, от лица которой производится попытка создать объект. При этом каждый сервер получит отдельную Windows-станцию. Это приведет к тому, что отдельные копии сервера (приложения) не смогут общаться между собой (и уж тем более с интерактивным клиентом), сервер будет ограничен правами конкретного пользователя, а такие вещи, как делегация, вообще будут невозможны. Применять данный вариант запуска нужно очень осторожно. Практически в любом случае можно найти другой выход (например, используя имперсонацию и подобрав подходящие параметры для функции CoRegisterClassObject). При выборе этого варианта загрузки поле реестра RunAs удаляется. Этот вариант запуска (как и предыдущий) недоступен, если сервер зарегистрирован как сервис.
  • This user – приложение будет запускаться под учетной записью, указанной в поле User (которое становится доступно после активизации данного варианта загрузки). Необходимо также задать пароль. При этом имя учетной записи проверяется на правильность, а вот с паролем можно и ошибиться. Чтобы уменьшить риск ошибки, диалог содержит поле для повторного ввода пароля. Но даже повторный ввод не спасет вас, если вы забыли выключить Caps Lock или русский язык. Самое противное, что о неправильности пароля вы узнаете только после того, как получите соответствующее сообщение об ошибке при попытке создать COM-объект. При выборе этой опции серверному процессу будет выделена отдельная Windows-станция. Это означает, что ваш сервер не сможет напрямую взаимодействовать с интерактивным пользователем. Если COM-сервер зарегистрирован как сервис (в реестре присутствует параметр LocalService), то сервер может быть активирован как обычный сервис (например, при старте системы). При выборе этого варианта запуска в параметр RunAs заносится имя учетной записи, под которой будет запускаться сервер.
  • The System Account – приложение будет запускаться под учетной записью SYSTEM. Этот пункт доступен, если сервер зарегистрирован как сервис (ATL-визард позволяет легко создавать такие серверы, необходимо только регистрировать их с опцией /service, а не /regserver). В этом случае настройки параметров загрузки можно задать в диалоге настройки сервиса. До появления W2k учетная запись SYSTEM не могла обращаться к сетевым ресурсам. В W2k и более старших версиях ОС учетная запись SYSTEM ассоциируется в сетевой среде с учетной записью компьютера, которому она принадлежит.

Если сервер должен взаимодействовать с интерактивным пользователем, нужно или написать отдельное клиентское приложение, или создать и зарегистрировать COM-сервер как сервис, указав при регистрации сервиса, что он должен иметь право взаимодействовать с рабочим столом. Сделать это можно в диалоге свойств сервиса (см. рисунок 9). Какой способ лучше? Я считаю – первый. По-моему, негоже серверу выпендриваться и лезть к незнакомым людям с вопросами и предложениями. Если пользователю будет нужно, он запустит утилиту администрирования и всласть наобщается с сервером. Если нужно оповещать пользователя, то, например, можно поместить клиентское приложение в папку Startup и вывести иконку в панели задач. При этом, если кому-то такой сервис не понравится, он сможет выгрузить и удалить надоеду.

Если нужно просто выдать сообщение, например, о критичном сбое, можно воспользоваться функцией MessageBox, передав ей в качестве последнего параметра флаг MB_SERVICE_NOTIFICATION. Это заставит выдавать сообщение на default desktop (не обращая внимания на Windows-станцию, в которой создан сервер). Будьте при этом осторожны, так как окна сообщений, показываемые с флагом MB_SERVICE_NOTIFICATION модальны по отношению к системе, то есть если пользователь не закроет такое окно, второе не будет выведено.

Защита в службах Windows и DCOM

Рисунок 9. Если включить переключатель, обведенный красной линией, ваш сервис сможет взаимодействовать с интерактивным пользователем.

Dcomcnfg не очень мощная, но порою незаменимая утилита. Нередко программист хочет избавить пользователя от использования этой утилиты, например, задавая настройки прямо из сервера (с помощью функции CoInitializeSecurity). Однако права активации всегда задаются через реестр, и их считывание происходит до загрузки сервера. Если хочется упростить жизнь пользователя, то следует или использовать COM+, или задавать необходимые настройки в момент инсталляции программы.

Категория: Службы и консоли | Добавил: masterov (01.12.2017) | Автор: Андрей Мастеров E W
Просмотров: 25 | Теги: Windows, службы | Рейтинг: 0.0/0
Всего комментариев: 0
avatar