安全接收事件

临时使用者和永久使用者采取不同的方法来保护事件传递。

本主题讨论以下部分内容:

保护临时使用者

临时使用者会持续运行到系统重新启动或 WMI 停止为止,但如果引发特定事件则无法启动。 例如,调用 SWbemServices.ExecNotificationQueryAsync 会创建临时使用者。

调用 SWbemServices.ExecNotificationQueryIWbemServices::ExecNotificationQuery 会创建临时事件使用者。 临时使用者无法控制向其所创建的事件接收器提供事件的人员。

可以同步、半同步或异步调用 ExecNotificationQuery 方法。 例如,SWbemServices.ExecNotificationQuery 是一种可以半同步调用的同步方法,具体取决于 iflags 参数的设置方式。 SWbemServices.ExecNotificationQueryAsync 是异步调用。

请注意,这些调用的异步版本对接收器的回调可能不会以与脚本调用相同的身份验证级别返回。 因此,建议使用半同步调用而不是异步调用。 如果需要异步通信,请参阅调用方法设置异步调用的安全性

脚本订阅者无法检查事件提供程序的访问权限来向脚本创建的接收器提供事件。 因此,建议对 SWbemServices.ExecNotificationQuery 的调用使用调用的半同步形式并使用特定的安全设置。 有关详细信息,请参阅使用 VBScript 进行半同步调用

保护永久使用者

永久使用者永久订阅来自事件提供程序的事件,这些事件将在重启操作系统后持久存在。 支持永久使用者的事件提供程序是事件使用者提供程序。 如果某个事件发生时事件提供程序未在运行,则 WMI 在需要提交该事件时会启动该提供程序。 WMI 根据 __EventConsumerProviderRegistration 实例(该实例将使用者提供程序 __Win32Provider 实例与使用者提供程序定义的逻辑使用者类相关联)识别应将事件传递到哪个使用者提供程序。 有关使用者提供程序角色的详细信息,请参阅编写事件使用者提供程序

永久使用者可以控制向其发送事件的人员,而事件提供程序可以控制访问其事件的人员。

客户端脚本和应用程序创建逻辑使用者类的实例,这属于订阅的一部分。 逻辑使用者类定义事件包含的信息、客户端可以对事件执行的操作以及如何传递事件。

WMI 标准使用者类 提供了逻辑使用者类的角色示例。 有关详细信息,请参阅借助标准使用者监视和响应事件

保护永久订阅

永久订阅在 WMI 中引发安全问题的可能性更大,因此具有以下安全要求:

  • 逻辑使用者实例、__EventFilter__FilterToConsumerBinding 实例必须在 CreatorSID 属性中具有相同的单独安全标识符 (SID)。 有关详细信息,请参阅在永久订阅的所有实例中保持相同的 SID

  • 创建订阅的帐户必须是具有本地管理员特权的域帐户或本地管理员组帐户。 使用管理员组 SID 使订阅能够继续在本地计算机上工作,即使订阅与网络断开连接也是如此。 使用域帐户可以准确识别用户。

    但是,如果未连接计算机且创建帐户是域帐户,使用者会因 WMI 无法验证帐户的标识而失败。 为避免在计算机与网络断开连接时订阅失败,请使用管理员组 SID 进行订阅。 在这种情况下,应确保 LocalSystem 帐户可以访问域中的组成员身份数据。 某些事件使用者提供程序的安全要求特别高,因为未授权订阅会造成巨大破坏。 示例为标准使用者、ActiveScriptEventConsumerCommandLineEventConsumer

  • 可以将永久订阅配置为仅接受来自特定事件提供程序标识的事件。 将 __EventFilter 实例的 EventAccess 属性中的安全描述符设置为事件提供程序标识。 WMI 将事件提供程序的标识与安全描述符进行比较,以确定提供程序是否具有 WBEM_RIGHT_PUBLISH 访问权限。 有关详细信息,请参阅 WMI 安全常量

    如果筛选器允许访问事件提供程序标识,那么它也信任事件。 这样,接收事件的使用者就能引发委派事件。

    注意:EventAccess 中安全描述符的默认值为 NULL,这允许所有人访问。 建议在 __EventFilter 的订阅实例中限制访问,以提高事件安全性。

设置仅限管理员的 SD

以下 C++ 代码示例在 __EventFilter 实例上创建仅限管理员的安全描述符。 此示例使用安全描述符定义语言 (SDDL) 创建安全描述符。 有关 WBEM_RIGHT_SUBSCRIBE 的详细信息,请参阅 WMI 安全常量

// Create SD that allows only administrators 
//    to send events to this filter. 
// The SDDL settings are O:BAG:BAD:(A;;0x80;;;BA)
// Set the EventAccess property in the 
//    IWbemClassObject of the __EventFilter instance. 
   long lMask = WBEM_RIGHT_PUBLISH;
     WCHAR wBuf[MAX_PATH];
     _ltow( lMask, wBuf, 16 );
 
HRESULT hRes = pEventFilterInstance->Put( L"EventAccess", 0,
    &_variant_t( L"O:BAG:BAD:(A;;0x80;;;BA)" ), NULL );

前面的代码示例需要以下引用和 #include 语句。

#define _WIN32_DCOM
#include <wbemidl.h>
#include <comdef.h>

#pragma comment(lib, "wbemuuid.lib")

模拟事件提供程序标识

永久使用者可能需要模拟事件提供程序来处理事件。 永久使用者仅在存在以下情况时才能模拟事件提供程序:

  • __FilterToConsumerBinding 的实例将 MaintainSecurityContext 属性设置为 True。
  • 事件在提供程序生成事件时所在的同一安全上下文中进行传递。 只有作为 DLL 实现的使用者(进程内使用者)才能在提供程序的安全上下文中接收事件。 有关进程内提供程序和使用者安全性的详细信息,请参阅提供程序托管和安全性
  • 事件提供程序在允许模拟的进程中运行。

运行使用者进程的帐户必须对 WMI 存储库(也称为 CIM 存储库)具有 FULL_WRITE 访问权限。 在订阅中,__FilterToConsumerBinding__EventConsumer__EventFilter 实例必须在 CreatorSID 属性中具有相同的单独安全标识符 (SID) 值。 WMI 将每个实例的 SID 存储在 CreatorSID 中。

SID 和永久订阅

当绑定、使用者和筛选器不是由同一用户创建时,永久订阅不起作用,这意味着 __FilterToConsumerBinding__EventConsumer__EventFilter 在 CreatorSID 属性中必须具有相同的单独安全标识符 (SID) 值。 Windows Management Instrumentation (WMI) 会存储该值。

使用域帐户创建永久订阅

使用域帐户创建永久订阅时,必须考虑多项问题。 在没有用户登录时,每个永久订阅仍应正常工作,这意味着订阅在内置 LocalSystem 帐户下运行。

如果域用户是安全敏感使用者(ActiveScriptEventConsumerCommandLineEventConsumer)的永久订阅的创建者,WMI 就会验证 __EventFilter 类、__FilterToConsumerBinding 类和使用者实例的 CreatorSID 属性是否属于相关用户(该用户是本地管理员组的成员)。

以下代码示例演示如何指定 CreatorSID 属性。

 instance of __EventFilter as $FILTER
    {
        // this is the Administrators SID in array of bytes format
        CreatorSID = {1,2,0,0,0,0,0,5,32,0,0,0,32,2,0,0};    
        // Add filter code here ...
    }

    instance of ActiveScriptEventConsumer as $CONSUMER
    {
       CreatorSID = {1,2,0,0,0,0,0,5,32,0,0,0,32,2,0,0};
       // Add consumer code here ...
    }

    instance of __FilterToConsumerBinding
    {
       CreatorSID = {1,2,0,0,0,0,0,5,32,0,0,0,32,2,0,0};
       Consumer = $CONSUMER;
       Filter = $FILTER;
       // Add binding code here ...
    }

对于跨域情况,将 Authenticated Users 添加到“Windows Authorization Access Group”。

保护 WMI 事件

接收 WMI 事件