COM Security in Practice

Rajiv Dulepet

Contents

Introduction
Registry
Activation Security
Call Security
Common Scenarios
References

Introduction

The Component Object Model (COM) can make distributed applications secure without any security-specific coding or design in either the client or the component. Just as the COM programming model hides a component's location, it also hides the security requirements of a component. The same binary code that works in a single-machine environment, in which security may be of no concern, can be used securely in a distributed environment.

COM provides two distinguishable categories of security. The first is termed activation security, and it controls which objects a client is allowed to instantiate. The second form is call security, which dictates how security operates at the per-call level on an established connection from a client to a server object.

This article describes the exact capabilities of COM security in greater detail.

Registry

Entries in the system registry can affect how COM security allows the activation and calling of objects by a remote client. COM provides mechanisms to externally configure security settings for objects and clients. In the current implementations of COM, all security policies are enforced at the process level. All objects in a process share the same security policies unless they programmatically override them. (Details on call security are provided later in this document.) To match this process-wide security configuration, COM introduces the concept of an application identifier, or APPID.

To change the security settings for the server, you can either edit System Registry entries directly or use the DCOMCNFG or OLE/COM Object Viewer utility.

Application IDs

APPIDs group the configuration options for one or more COM objects into one centralized location in the registry. COM objects hosted by the same executable must map to the same APPID. In-process COM objects on a single machine that are run remotely can be forced into the same surrogate process by assigning the same APPID to their Class ID (CLSID) entries.

DCOMCNFG

DCOMCNFG is a utility you can use to configure various COM-specific settings in the registry. This configuration utility, dcomcnfg.exe, is included in the Microsoft® Windows NT® operating system and is used to configure applications to use COM. The dcomcnfg.exe utility is not added to the Start menu or any groups during installation of Windows NT version 4.0. An administrator must start it from the Run command on the Start menu.

DCOMCONFG must be used to configure an application's COM properties before the application can use COM to communicate over the network. The DCOMCONFG utility can be used to:

Both the computers that are running the client and the server applications must be configured for a distributed environment with the DCOMCONFG utility:

When DCOMCNFG starts, it displays the Distributed COM Configuration Properties dialog box. This dialog box has three tabs: Default Security, Default Properties, and Applications.

Default Security

You can use the Default Security tab to specify default permissions for objects on the system. This tab has three sections: Access, Launch, and Configuration. To change a section's defaults, click the corresponding Edit Default button. These default security settings are stored in the registry under HKEY_LOCAL_MACHINE\Software\Microsoft\OLE.

Figure 1. The Default Security tab

Default Properties

On the Default Properties tab, you must select the Enable Distributed COM on This Computer check box if you want clients on other machines to access COM objects running on this machine. Selecting this option sets the HKEY_LOCAL_MACHINE\Software\Microsoft\OLE\EnableDCOM value to Y.

Figure 2. The Default Properties tab

Applications

You can change the settings for a particular object from the Applications tab. To do so, you select the application from the list and click the Properties button. This action displays the Object Properties dialog box for the selected application.

Figure 3. The Applications tab

The Object Properties dialog box has four tabs:

Figure 4. The Object Properties dialog box

OLE/COM Object Viewer

The OLE/COM Object Viewer (OLEView) is an administration and testing tool for developers and power users. It is the second way to configure security options for a component. With the OLE/COM Object Viewer, you can:

Figure 5. The OLE/COM Object Viewer

OLEView provides more information than DCOMCNFG, and you can use it for all the settings done by DCOMCNFG except one: OLEView has no way to set the COM server to "RunAs" a certain user. The other major difference between DCOMCNFG and OLEView is that DCOMCNFG shows only the servers with APPIDs. OLEView allows the component to use Default Access and Launch permissions, but unlike DCOMCNFG it doesn't allow the user to modify the Default settings.

In essence, OLEView provides all the functionality provided by clicking the Properties button in the Application tab of DCOMCNFG except for RunAs identity, and it also provides a subset of the Default Properties and Default Security tabs of DCOMCNFG.

Activation Security

Activation security controls which classes a client is allowed to launch and retrieve objects from. The Service Control Manager of a particular machine automatically applies activation security. Upon receipt of a request from a remote client to activate an object (see the client activation services outlined earlier in this document), the Service Control Manager of the machine checks the request against the following information stored within its registry:

These settings are described in the following sections.

Machine-wide Settings for Securing Activation

The following named values, which appear under HKEY_LOCAL_MACHINE\Software\Microsoft\OLE, control the global activation policies of the machine. Only machine administrators and the system have full access to this portion of the registry. All other users have read-only access.

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Ole]
   "EnableDCOM"="Y"
   "DefaultLaunchPermission" = hex: [self-relative security descriptor]

The EnableDCOM named value allows or disallows remote clients to launch class code and connect to objects for the system. The DefaultLaunchPermission named value, as the name implies, sets the default access control list (ACL) to specify who has access to classes on the system.

Per-Class Settings for Activation

The following key may be added under any class's APPID key (HKEY_CLASSES_ROOT\APPID\{...}) to limit activation by remote clients of specific classes. By definition, Launch security needs to be enforced by the COM libraries themselves, since the object that could potentially perform this check has not been instantiated yet. For this reason, launch security can only be externally configured and cannot be controlled programmatically.

Activation security is automatically applied by the Service Control Manager (SCM) of a particular machine. Upon receipt of a request from a remote client to activate an object, the SCM on the server machine checks the request against the HKEY_CLASSES_ROOT\AppID\{...}\LaunchPermission key, which contains data describing the access control list (ACL). If the user's access control entry (ACE) is not contained within the ACL, access is denied. If the APPID does not have a LaunchPermission key, the SCM checks the request against the ACL in the DefaultLaunchPermission key under HKEY_LOCAL_MACHINE\Software\Microsoft\OLE.

Launch security affords administrators granular control over who can instantiate COM objects for use by others and therefore protects business processes (as an example) from malicious or accidental initialization. For example, you may want to restrict instantiation of accounts-payable processes to employees in the Accounting group, or you may want to develop a COM server as a Windows NT service that can be started only by a specific service account.

Using the DCOM Configuration utility included with Windows NT (dcomcnfg.exe), an administrator can control activation security at both the machine level and the object level. In addition to launch security, an administrator can control who can access a particular object (access security) and who can alter registry settings related to a particular object (configuration access).

If an account may both launch and access an object, the account must appear on both the Launch and Access security access lists. DCOMCNFG does not enforce this constraint.

Call Security

COM provides two mechanisms to secure calls. The first is similar to DCE RPC: COM provides functions and interfaces that applications can use to do their own security checking. The second mechanism is run automatically by COM. If the application provides some setup information, COM will make all the necessary checks to secure the application's objects. This automatic mechanism does security checking for the process, not for individual objects or methods. Applications requiring more fine-grained security can perform their own security checking. The two mechanisms are not exclusive: an application can ask COM to perform automatic security checking and also perform its own.

COM call-security services are divided into three categories: general functions called by both clients and servers, new interfaces on client proxies, and server-side functions and call-context interfaces. The general functions initialize the automatic security mechanism and register authentication services. The proxy interfaces allow the client to control security on calls to individual interfaces. The server functions and interfaces allow the server to retrieve security information about a call and to impersonate the caller.

In a typical scenario, the client queries an existing object for IClientSecurity, which is implemented locally by the interface remoting layer. The client uses IClientSecurity to control the security of individual interface proxies on the object, prior to making a call on one of the interfaces. When a call arrives at the server, the server can call CoGetCallContext to retrieve an IServerSecurity interface. IServerSecurity allows the server to check the client's authentication and to impersonate the client, if needed. The IServerSecurity object is valid for the duration of the call. The client can call CoInitializeSecurity to establish default call security for the process, avoiding the use of IClientSecurity on individual proxies. CoInitializeSecurity allows a server to register automatic authentication services for the process. Registering authentication services with CoRegisterAuthenticationServices does not prevent calls from arriving with no authentication service or with an unregistered authentication service.

Implementations of QueryInterface must never check ACLs. COM requires that an object that supports a particular IID always return success when queried for that IID. Even if COM did not enforce that requirement, checking ACLs on QueryInterface would not provide any real security. If Client A legally has access to interface IFoo, Client A can hand a pointer to IFoo directly to Client B without any calls back to the server. Additionally, COM caches interface pointers and will not call QueryInterface on the server every time a client does a query.

Each time a proxy is created, COM sets the security information to default values, which are the values used for automatic security.

The flow of control looks something like this for client/server negotiation:

  1. Default authorization and authentication levels are set in CoInitializeSecurity. Authentication and authorization services can be registered with CoRegisterAuthenticationServices. If you call this function, you cannot also call CoInitializeSecurity. Authorization and authentication levels, Server Principle Name, and authorization-specific information can be set by calling IClientSecurity::SetBlanket. This information applies to the specific proxy.

  2. COM determines the appropriate authentication service that supports the client's requirements, based on the information obtained in step 1. Currently only NTLMSSP is supported as an authentication service. The security attributes specified by the client are compared to those for the server as specified in the call to CoInitializeSecurity. If the client specifies requirements less than those specified by the server, the call will fail.

  3. The programmer can have the server call IServerSecurity::QueryBlanket to further evaluate the requirements of the client. The server application using this interface could decide to reject the client's call based on insecure authentication or impersonation level, despite what is specified in CoInitializeSecurity. This behavior would be typical if the server handled general product information queries but was now required to complete a credit card transaction. CoInitializeSecurity could initialize the server to have low security channels by default, but for ICreditCardTransaction, an encrypted secure channel is required.

  4. With mutual authentication such as that offered by Kerberos V, a similar process may happen on the client side to verify that the server is not an impostor. Because of limitations in NTLMSSP, this functionality is not currently supported.

Machine-wide Settings for Call Security

The following named values appear in HKEY_LOCAL_MACHINE\Software\Microsoft\OLE and control COM call-level security capabilities in applications that do not call CoInitializeSecurity. Only machine administrators and the system have full access to this portion of the registry. All other users have read-only access.

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Ole]
   "DefaultAccessPermission" = hex: [self-relative security descriptor]
   "LegacyImpersonationLevel" = dword:2
   "LegacyAuthenticationLevel" = dword:2
   "LegacyMutualAuthentication"=dword:2
   "LegacySecureReferences{ XE "LegacySecureReferences"}"=dword:2

Per-Class Settings for Call-Security

The following named values can be added under any class's APPID key (HKEY_CLASSES_ROOT\APPID\{...}) to limit access to objects of a specific class.

AccessPermission{ XE "AccessPermission" }{ XE "Registry Keys:AccessPermission}

This named value is of type REG_BINARY. It contains data describing the ACL of the principals that can access instances of this class. Upon receiving a request to connect to an existing object of this class, the ACL is checked while impersonating the caller. If the access check fails, the connection is disallowed. If this named value does not exist, the machine-wide DefaultAccessPermission ACL is tested in an identical manner (see above) as a default to determine if the connection is to be allowed.

Call-Level Security

Common Scenarios

This section illustrates how COM security can be used in some common scenarios.

Windows 95 COM Servers

When a Windows 95 COM server is used to serve objects to remote clients, make sure to:

  1. Verify that the EnableDCOM and EnableRemoteConnections registry keys under HKLM\Software\Microsoft\OLE are set to Y on the server machine. EnableDCOM must be set to Y to enable any distributed COM functionality. EnableRemoteConnections must be set to Y to let the machine act as a server.

  2. On a Windows 95 computer, manually start the server. Windows 95 does not support launching servers through COM.

  3. If your server resides in a single-thread apartment (STA), try manually launching %systempath%\rpcss.exe before manually launching the server application. There are certain circumstances where DCOM for Windows 95 does not properly launch RPCSS for STA servers. Microsoft has confirmed this to be a problem in DCOM for Windows 95. We are researching this problem and will post new information as it becomes available. If manually launching RPCSS resolves the RPC_SERVER_UNAVAILABLE error, you can automatically launch RPCSS during system startup. To do so, add a named value with the value "RPCSS.EXE" to HKLM\Software\Microsoft\Windows\CurrentVersion\Run, which launches when the shell loads, or \RunServices, which launches immediately upon machine startup (before logon).

Windows 95 client and Windows NT Server

The authentication level is negotiated as follows: If you have a Windows 95 client with authentication level Connect and a Windows NT server object with authentication level Encrypt, COM will try to use Encrypt for calls in both directions. Since Windows 95 cannot receive calls at Encrypt, the Windows NT computer cannot call the Windows 95 machine. Thus both the client and server have to set the authentication level to the lowest value allowable for any call in any direction.

Similarly, if you have two processes, one with a logon token and the other with an impersonation token, and you set the authentication level to none in the second, it still won't be able to call the first if its authentication level is not none.

Windows NT Workstation's Network not in Domain

Please refer to "FAQ: COM Security Frequently Asked Questions," Knowledge Base article #Q158508, in the MSDN™ Library.

Legacy COM Application

Three named values in the registry apply to legacy code written before DCOM. These named values exist under the HKEY_LOCAL_MACHINE\Software\Microsoft\OLE\legacy key, and COM uses them to determine what parameters to pass to CoInitializeSecurity on the server's behalf:

Microsoft Internet Information Server and COM

Launching a COM object on a computer running the Windows NT 4.0 operating system requires certain permissions. This is not normally an issue for most interactive users, because the default permissions for launching and accessing COM objects on Windows NT allow access to anyone interactively logged on to the local machine. A Microsoft Internet Information Server (IIS) application, whether it is running in the context of the IUSR_<servername> account or as an impersonated user account from Basic or NTLM authentication, is not interactively logged on. Therefore, the default permissions for launching and accessing COM objects will not allow an ISAPI extension dynamic-link library (DLL), computer graphics interface (CGI) application, or Internet script to launch these objects successfully by default.

With the DCOMCNFG utility on Windows NT 4.0, you can set the default permissions for all COM objects on your machine. You can use DCOMCNFG to provide COM access to the IUSR_<servername> account, as well as to all user accounts that might be impersonated by your IIS configuration. You can even grant permissions to the "Everyone" group.

However, providing global access to all COM objects may not be in your best interests, so you can use DCOMCNFG to specify permissions for specific applications. In this way, you can provide access only to the applications you will need to access from your IIS application. COM applications can also determine what permissions are associated with launching and accessing themselves. To do so from inside your COM server, see the documentation for the CoInitializeSecurity function new to Windows NT 4.0, as well as that for CoCreateInstanceEx (in particular, the COSERVERINFO and COAUTHINFO structures) for manipulating COM access from the client side.

For more information on launching COM servers from ISAPI applications, see the "References" section of the article.

COM requires all of the permissions discussed above. In addition, it needs to access resources across the network. If a request is received using anonymous authentication, the IUSR_<servername> account username and password credentials will be used to connect to the remote COM server. Unless your IIS server machine is also a domain controller, the remote machine by default will not be able to determine who the IUSR_<servername> account is. (It exists only on the local IIS server machine.) Adding access and launch permissions to the group "Everyone" does not help in this case, because COM will not map access by an unknown account to the guest account in the same way that the LAN Manager service does for file sharing. The COM server machine must explicitly know the account that is being used.

When IIS applications are accessing resources (including COM resources) on remote machines, all the machines involved must participate in a domain relationship. Then, in Internet Manager, you can change your anonymous account to an account in the local or trusted domain. Now all machines in the domain structure will recognize the account and can explicitly add and delete access to their network resources for that account or for any groups that account is a member.

Be aware that if basic authentication is used for an IIS request, access to network resources (including COM servers) will be provided in the context of the user whose credentials were passed with the request. If the user specified does not have permissions to launch or access the COM server, the request will fail.

If the IIS request is validated using NTLM authentication, the impersonation level does not imply knowledge of the user name and password credentials. Therefore, access to network resources, regardless of the permissions on the resource, will be denied (with the exception of null session resources).

Launching OLE Servers from ISAPI Extensions

Please refer to "HOWTO: Launching OLE Servers from ISAPI Extensions," Knowledge Base article #Q156223, in the MSDN™ Library.

Interaction of Visual Basic and Internet Explorer COM Clients with COM Servers

Since Microsoft Visual Basic® and Microsoft Internet Explorer COM clients cannot call CoInitializeSecurity, you need to set the default authentication level to "None."

COM Client/Server Application Demonstrating Call-Level Security Functions

In this section we will use the Sales Training Roadmap sample application to demonstrate how call-level security functions are used. In this application, the engineers and managers have a training plan. The application has the following characteristics and rules:

The application is implemented as a Training COM object connected to a Microsoft SQL Server™ database. The implementation consists of one COM object with three interfaces: IEngineer, IManager, and IDatabase. IDatabase is an internal interface and is not accessible by the client. The object runs as an out-of-process server accessed by remote clients. Users are identified by their Windows NT logon ID. The out-of-process server is started as a Windows NT Service running as "System".

interface IEngineer {
HRESULT Read ( ... );                /* Read one's training plan. */
HRESULT Submit ( ... );              /* Submit a new training plan. */
   };
interface IManager {
   HRESULT Read ( ... );             /* Read anyone's training plan. */
HRESULT Approve ( ... );             /* Approve a training plan. */
   };

   interface IDatabase {
      HRESULT ReadRecord ( ... );    /* Read a database record. */
      HRESULT WriteRecord ( ... );   /* Write a database record. */
   };

The following describes one possible use of COM security for the training scenario. In this example, we will look only at security on the Training class.

  1. Two Windows NT groups, Engineer and Manager, are created. Administrator can map to an existing group.

  2. An ACL (query rights) for Engineer and Manager is placed on:
    \CLSID\{5cb31e10-2b5f- ... }\AccessPermission
    \CLSID\{5cb31e10-2b5f- ... }\LaunchPermission = Y
    

    These registry entries and ACLs prevent anyone but an Engineer or Manager from activating or accessing a Training object or its interfaces.

  3. To set authentication and authorization levels, the server calls CoInitializeSecurityCall.
CoInitializeSecurity (
/* Specifies access security for this process */
   pDefaultAccessACL,
   RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,    /* Insure data is not changed */
   RPC_C_IMP_LEVEL_IMPERSONATE,        /* Allow impersonation. */
   NULL);
  1. COM security does not currently support declarative (automatic) security checking at the interface level, so the client principal must be checked by the server to ensure it is a member of the groups allowed to call methods on a given interface. If the application was repartitioned into classes according to security requirements (Engineer and Manager classes with ITraining interfaces), COM declarative access security could then be used.

    To implement security at the interface level, the following must be coded on the server side.

    CoGetCallContext (IID_ServerSecurity, pSSecurity);
    pSSecurity->QueryBlanket (NULL, NULL, pszPrinciple, NULL, NULL, NULL, NULL);
    
    /* From here we want to take the principal name (which is the login of the client) and call whatever interface(s) necessary to determine if the client is in the appropriate group to call the interface. Something along the lines of: */
    
    if (IsPrincipleInGroup (pszPrincple, "MANAGER") == FALSE)
        return E_SECURITY_VIOLATION;
    
  2. All the application logic (business rules) specified above must be implemented by obtaining the principal name, possibly mapping it to a SID or database key, and using it in application logic. For example, for the rule, "All users can read their own training plan," the client principal is mapped to a database key to do the database query to obtain the corresponding training record. The principal in raw form could be used as the key.

References

The following topics are all available in the MSDN Library.

Component Object Model (COM) Specification 0.9 (Specifications bin)

"DCOM Architecture" by Markus Horstmann and Mary Kirtland.

ActiveX SDK (SDK Documentation bin).

"FAQ: COM Security Frequently Asked Questions," Knowledge Base article #Q158508.

Microsoft Transaction Server 2.0 (SDK Documentation, Platform Documentation, COM and ActiveX Object Services).