Securing a Server Application

Controlling access to your components via role-based security is all fine and well, but there is more to security than just access control. You must still set the security identity for your application and set the authentication and impersonation levels. Configuring security for a server application is different from that of a library application, justifying each application type in a separate section.

When designing and configuring a server application security, you need to do the following:

  • Decide on the security identity under which the server application executes.

  • Decide what authorization (access control) the server application requires—how granular access control should be.

  • Decide at what authentication level to authenticate incoming calls.

  • Decide at what impersonation level you grant objects in other applications when this server application is the client of those objects.

  • Configure your server application security.

The following sections discuss these action items in depth.

Configuring the Server Application Identity

When you invoke the Application Install Wizard and use it to create a new server application, the Wizard presents you with a dialog box that lets you set the security identity of the server application. Setting the security identity determines what user account all components in that application will run under, which dictates credentials, privileges, and access rights (see Figure 7-8). You may either run the application as the interactive user (useful during debugging) or as a designated user (for deployment).

Selecting an identity for a new server application

Figure 7-8. Selecting an identity for a new server application

You can always set a different identity later on (and you usually will) by bringing up the application properties page and selecting the Identity tab (see Figure 7-9).

Selecting an identity for an existing server application

Figure 7-9.  Selecting an identity for an existing server application

When Object A is created in the application, the application security identity controls everything Object A is allowed to access and do. If Object A tries to access another object (Object B) in another application, and Object B is configured to use role-based security, COM+ uses the security identity of Object A to determine whether to grant access to Object B. The security identity of Object A has to belong to at least one role that Object B allows access to. But there is more to an object’s identity than role-based security: accessing the filesystem, accessing Win32 handles, installing new components, accessing the COM+ Catalog, modifying the Registry, remote calls, and so on, are all limited by the privileges of the security identity.

To make an educated decision on selecting the right identity for your objects, you need to know the term Windows station. In Windows, every user, or more precisely, every security identity, gets to run in its own station—it has its own copy of the clipboard, global atoms table, desktop objects, a keyboard, a mouse, and a display device. Each logged-on user is provided with a new Windows station. Obviously, only the Windows station associated with the currently interactive user can actually display a user interface. If a component is set to run under a designated security identity and that identity is different from that of the interactive user, it is placed in its own Windows station.

When you configure your server application identity to run under the account of the interactive user, the application shares the interactive Windows station with that user. This option has the clear benefit of being able to interact with the user. However, it also has severe limitations: what should COM+ do if no user is logged on and an activation request from another machine tries to launch the application? In this case, COM+ refuses to launch the application. If the interactive user logs off, COM+ also terminates the application.

The second option COM+ provides for configuring a server application’s identity is to run under a specific designated identity. The application is placed in its own Windows station. All subsequent instantiations of new components from that application share that dedicated windows station and identity credentials. The component in the application cannot have a user interface because their Windows station cannot interact with the user. However, for a middle-tier component, a user interface is not necessary anyway; all user interaction is performed at the presentation tier. You can still redirect message boxes to the interactive Windows station, using the message box type attribute MB_DEFAULT_DESKTOP_ONLY . This redirection is done by design for debug purposes and is available for message boxes only.

So, which of the two options should you choose? Running as the interactive user has a distinct advantage during debugging sessions, because you can use a debugger to trace the execution of your components. In addition, during a debug session, the developer is logged on to his machine, so COM+ activates the application easily. Running as a designated user is more useful for deployment purposes. It frees you from needing a user logged on to the server machines when your application is running. If you configure more than one application to run under the same designated user account, you also conserve system resources because all components from those applications share the same Windows station. Running under a specific identity has a few more advantages:

  • Because an object can perform operations on behalf of arbitrary users, limiting the object’s capabilities is often necessary. By assigning the object a less privileged identity, you limit the potential harm malicious callers can do after being granted access the object (the interactive user may have unlimited administrator power, and that could be very dangerous indeed).

  • Internet clients calling into your application have no identity at all and are anonymous in most cases. You can now assign a specific identity to the objects that carry out a request on behalf of Internet clients.

Enabling Authorization

The properties page of each COM+ server application includes a Security tab. The security tab is where you set the rest of the security properties for your application. There are four settings on this tab, each discussed in the following sections. At the top of the tab (see Figure 7-10), you will find the authorization checkbox.

A server application Security tab

Figure 7-10.  A server application Security tab

The authorization checkbox is the access security master switch for the application (The component’s developer still has to enable the component-level authorization on a component by component basis, as discussed previously; see Figure 7-3). When you install a new COM+ application, either a library or a server application, the default setting for this switch is off. You must turn on authorization yourself by checking the checkbox to enable role-based security for your application. When authorization is enabled, COM+ verifies in every call that the calling identity is a member of at least one of the roles defined for the application, and denies access if it is not. If the caller is a member of at least one role, but the target component does not grant access to any of the roles the caller is a member of, the call is denied access downstream at the component level. Application-level authorization is also the COM+ way of enforcing launch control. The caller cannot launch a new process (by trying to create an object) if it is not a member of at least one role.

Setting the Security Level

The Security Level properties group (which consists of two radio buttons; see Figure 7-10) is the center of the Security tab. This group is the role-based security master switch for all the components in this application. If you set it to the upper position (“Perform access checks only at the process level”), all role-based security configurations at lower levels (component, interface, and method) will be disabled and ignored (see, for example, the bank component security tab in Figure 7-11). When access checks are performed at the process level only, all calls will be allowed through regardless of the settings at the lower levels, as long as they passed the generic application-level security access check.

Setting the security access check to be done at the process level only disables component-level security

Figure 7-11.  Setting the security access check to be done at the process level only disables component-level security

One side effect of performing the security checks at the process level only is that you cannot make any programmatic role-based security checks inside your components because the security information will not be part of the call object. You cannot access interfaces such as ISecurityCallContext. Additionally, when new objects are activated, COM+ ignores their security requirements when deciding in which context to activate them.

When you set the access security to be performed at the process level and the component level, you can take advantage of role-based security, either administratively or programmatically. COM+ considers the object security requirements when deciding on its activation context. Components that do not want to use role-based security can still choose to do so.

As you can see, disabling component-level security checks globally for an application is of little use to you. You can always disable it on a component-by-component basis.

Setting the Authentication Level

Next, you need to configure the desired authentication level by selecting values from the “Authentication level for calls” combo box (see Figure 7-10). The authentication level controls both caller identity authentication and data integrity authentication. The configured authentication level affects all calls to and from the application.

COM+ lets you set the authentication level to one of six settings: None, Connect, Call, Packet, Packet Integrity, and Packet Privacy. The first four authentication levels deal with the caller’s identity only and the last two add data integrity as well.

Authentication = None

When the authentication level is set to None, you instruct COM+ not to authenticate the caller at all. If the caller claims to be Joe Customer, then he is believed to be so. Clearly, disabling authentication exposes your application and renders it completely defenseless to anything ranging from innocent user mistakes to malicious third-party attacks. Setting authentication to None may be useful in isolated cases when clients calling in are anonymous and no data privacy or integrity guarantee for data in transit is required. However, you should generally avoid disabling authentication completely.

Authentication = Connect

When the authentication level is set to Connect, COM+ authenticates the user identity only when a client connects to an object in the application. Connecting to the object means creating the object or trying to access an object (given to the client from another client) for the first time. COM+ uses the challenge/response protocol to authenticate the client’s identity. If the same client tries to connect to another object, COM+ authenticates the client’s identity again. However, COM+ stays out of the way once a connection is established. This approach to authentication leaves the door open for a malicious third party to sniff the network, wait for COM+ to authenticate a genuine caller, and then make subsequent calls in place of the legitimate caller, because future calls are not authenticated. Connection-level authentication is the bare minimum required for meaningful role-based security because it verifies at least once that the caller is who it says it is. Connection-level authentication, however, provides no privacy or integrity guarantee for the data in transit.

Authentication = Call

When the authentication level is set to Call, COM+ authenticates the caller’s identity using challenge/response on every method call to every object in the application, not just the first call. This approach is clearly an improvement over authentication done only at connection time.

Authentication = Packet

Authenticating at the beginning of every call may not be secure enough if the method invocation payload is spread over multiple network packets. The underlying network transport protocol may divide the payload (parameters, returned value, source and destination, and so on) over multiple packets regularly. A determined malicious third party may wait for the first packet to be authenticated, and then intercept the rest of the packets, change them, or send his own. To handle this possibility, you can instruct COM+ to authenticate each packet from the caller, not just the first packet of every call. This level of authentication is the default used for every new COM+ server application. Packet level authentication may be the first meaningful authentication setting. However, it still provides no privacy or integrity guarantee for the data in transit.

Authentication = Packet Integrity

The previous four authentication levels dealt with authenticating the caller’s identity only. Authenticating every packet from the caller would prevent a malicious third party from being tempting to be the caller or pretending to change the packet flow. However, nothing stops a malicious third party from modifying the packets’ content. The malicious third party could still, for example, change parameter values inside individual packets.

By setting the authentication level to Packet Integrity, you instruct COM+ to append a hashed checksum to each packet. The receiving side calculates the checksum on the packet just received, and if the resulting checksum differs from that appended to the packet, COM+ fails the call. Packet integrity increases the packet size and network transport time, but it provides a data integrity guarantee. Authenticating data integrity is done on top of packet-level identity authentication.

Authentication = Packet Privacy

Although the Packet Integrity level of authentication protects the data integrity of each packet, the malicious third party can still read the packets’ content. If you want to protect the privacy of the information, you can instruct COM+ to not only provide packet integrity with a checksum, but also to encrypt the packet’s content when in transit and decrypt it when it is received. Packet Privacy is the highest authentication level possible, providing you with authenticated caller identity, data integrity, and privacy for data in transit on every network packet. You will encounter a performance hit for the extra computational effort of encrypting and decrypting every packet. However, for many enterprise applications, this level of security may be required to protect sensitive data properly according to organizational security policy.

Deciding on the authentication level

Every authentication setting offers a clear tradeoff of application security versus performance. You should decide on the right authentication level based on the nature and sensitivity of the services your components expose, potential-threats analysis, and the calling pattern from your clients (the lower the call frequency and the longer the method execution time is, the less noticeable the authentication penalty will be). The application authentication setting affects all components in your application. If the components in your application differ greatly in their authentication needs, consider putting the more sensitive components in a separate application and configuring that application to have a higher level of authentication. Don’t make components pay for an authentication level they do not require.

On the other hand, if your threats analysis demands an authentication level that degrades the application performance significantly, or if trade-off is impossible because of organizational security policy, upgrading hardware to improve application performance is an option.

Client authentication level compatibility

COM+ prefers to secure the server as much as possible. If the calling client uses an authentication level lower than that of the server (for example, if the client is configured to use Connect and the server application is configured to use Packet), then COM+ fails the call. If, on the other hand, the server is the one using the lower setting, COM+ promotes the connection to the client level.

Setting the Impersonation Level

When an object in Application A calls another object in Application B, identity issues are straightforward: each application has its own identity, used to decide whether to grant access to objects or to resources such as files. However, suppose that Application B needs to access an object in Application C to continue its work on behalf of the original caller in Application A. The immediate question is, under what identity should B access C? Should it access C as B or as A? Suppose that the object in C needs to call back into Application A to complete its work. Should it access Application A as C, B, or A?

One approach would let the server objects impersonate the client. This would be fine in an ideal world, where servers are never malicious. However, in an ideal world, you don’t need security either. Clearly, client applications need to declare what identity the servicing objects could use when accessing another application or a secured resource. This is what impersonation is all about. The Impersonation level combo box (see Figure 7-10) is at the bottom of the server application security tab. The impersonation level selection is used only when the application you configure is acting as a client of an object in another application. The impersonation level is really a measure of trust—how much this application trusts another application when it acts on its behalf. Does this application allow other objects to find its security identity? Does it allow them to impersonate itself and perform their work under the client identity, trusting the other applications’ objects not to abuse the trust? Does it allow the objects to make additional calls with the original client security identity? These are important questions from any client application perspective. COM+ defines four levels of trust, or impersonation levels: Anonymous, Identify, Impersonate, and Delegate.

Tip

Impersonation of any level requires authentication to be at least Connect (that is, any authentication level except None) to propagate the client identity to the server side.

Impersonation = Anonymous

Anonymous is the least trusting impersonation level. The client does not even allow any server object to learn the security identity of the client.

Impersonation = Identify

When the client sets the impersonation level to Identify, the server can identify the client—that is, obtain the security identity of the calling client. The server object is not allowed to impersonate the client—everything the object does is still done under the server’s own identity. Note that allowing or preventing the object from identifying the caller is not the same as having the object learn programmatically whether the caller is a member of a particular role. When the object queries for the caller’s role membership (you will see how later on), the question and the answer are in role terms (Bank Manager, Teller) and not in identity terms (Joe Customer).

Impersonation = Impersonate

When the client application sets the impersonation level to Impersonate, the object can impersonate and assume the client identity’s credentials. This impersonation level is the default value COM+ uses for new applications. Impersonation indicates a great deal of trust between the client and the servicing object; the server can do anything the client can do, even if the server application is configured to use a less privileged identity. The only difference between the real client and the object is that if the object is on a separate machine from the client, it cannot access resources or objects on other machines as the client. This lack of access is a direct result of the underlying authentication mechanism—the challenge/response protocol. If the object, impersonating the client, tried to access another machine while claiming to be the client, it would fail to authenticate itself as the client because it does not know the client’s password. If the object and the client were on the same machine, the object impersonating the client could make one network hop to another machine, since the machine it resides on could still authenticate the client identity—but it could go no further.

Impersonation = Delegate

The only difference between delegation and impersonation is that with delegation, the object can freely access any object on any machine as the client. If any of these server objects use delegation, the client identity could be propagated further and further down the call chain. Delegation is possible because Windows 2000 can use the Kerberos authentication service, which uses a different authentication method than challenge/response. Both the client and server user accounts must be configured in the Active Directory properly to support delegation,[4] (in addition to the client granting authority to do delegate-level impersonation), due to the enormous trust (and hence, security risk) involved. Delegation uses, by default, another security service called cloaking, which propagates the caller identity along the call chain. Delegation is extremely dangerous from the client perspective because the client has no control over who uses its identity or where. When the impersonation level is set to Impersonate, the client takes a calculated risk because it knows which objects it was accessing. If those objects are on a difference machine, the client identity could not have propagated across the network.



[4] For more information, see Windows 2000 Administration in a Nutshell by Mitch Tulloch (O’Reilly, 2000).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset