Security, Operational Management, and Communications Policies

Summary

Introduction

Organizational policies are basically rules that determine how an application is secured, managed, and how different components communicate with each other, These policies and their effect on distributed application design are shown below:

For example, the security policy which determines how users are authenticated (among many others) can greatly influence the design of various parts of the system. Should users be authorized using Windows logon or using a custom authorization scheme? What about service agents that receive messages from external services - how secure are these incoming messages? Similar questions apply to communication and operational management - for example, how are going to monitor the health of remote servers? The answers to these questions greatly affects design decisions.

Security, operational, and management policies and their effect on the architecture of distributed applications are described below:

Designing Security Policies

The security policy is concerned with authentication, authorization, secure communication, auditing, and profile management as shown below:

The following sections are covered:

General security guidelines

Consider the following general security guidelines when designing a security policy:

Authentication

It should be a design goal that components see authorization as a transparent process. For example, it is considered a bad design if user information needs to be passed along components just for authorization. It should also be a design goal that the relevance of the user identity is reduced the further the activity is from the user interface. For example, in service-based solutions, some activities may not even be initiated by users. 

Consider the following user scenarios:

Authentication in the Presentation Layer

Note these two important points regarding authentication in the presentation layer:

Windows-based UI usually authenticate users with their Windows log-on identity. Whereas Web-based applications have a wide-range of authentication mechanism (integrated Windows authentication, passport authentication, forms-authentication, and so on.)

Authentication in Business Components

For business components, the caller may be of many types and with different identities. For example:

User Type Possible Identity
UI component Some Windows logon account
UI process component.
Another business component A service account representing a run-time identity of a particular portion of the application. Or it could be a special service account for calls coming from external services.
A business workflow

Given the different types of callers and the different possible identities, business components must consider how to authenticate the caller and how this authentication can affect authorization.

Authentication in Data Access Components

Data access components are typically not exposed for calling from external scripts or other applications so you can design them to rely on the security context of the caller (Principal object of the thread). In general, data access components authenticate with the database in two main ways:

In general, it is best to use a limited set of service accounts that represent roles of user types. For example, in an e-commerce application, you could use could selectively log-on as OrderProcessingAccount, RefundAccount, or ReturnsAccount and assign each such account the appropriate database permissions. 

Authentication in Business Entity Components

If your business entity components will not be used by other applications (as part of an object model), then you do not need to present an authentication boundary. In this case, they should rely on the current security context (provided by System.Security.Principal.WindowsPrincipal object) for authentication.

If your business entity components will be used by other applications (as part of an object model), then you do need to present an authentication boundary, perhaps in the form of an extra component that helps the client to 'log-on' from code and if you are not relying on platform authentication, sets the security context required by these objects 

Authorization

In simple terms, authorization determines who can do what. To properly design an authorization policy, you need to take into account two issues:

In some cases, you may need to implement custom authorization checks. For example, you may only users that are managers can be authorized to change system settings. These types of authorization checks are better performed by the application as programmatic checks. You may even implement these checks using declaratively using attributes or configuration settings.

Designing Custom Application-Level Authorization Schemes

Having a custom authorization scheme is a common requirement. Consider the following guidelines when designing a custom application-level authorization scheme:

Users and Roles in Applications

An application interacting with services may have separate user accounts and role definitions - unless they were developed in an enterprise where users and groups were defined organization-wide. When dealing with interacting services, it is recommended that users are authenticated and authorized at a service-wide granularity. For example, if your application interacts with 5 different services, then service-wide granularity means defining roles such as StandardPartner, PremierPartner, and so on. Using service-wide granularity allows your application to grow and work with many partners in the future without affecting code or design.

Security Contexts at System Boundary

A custom principal on a given thread does not flow across processes or through remoting channels. At system boundaries, you usually have to set the security system yourself and this involves the following:

See Principal and Identity Objects in .NET Security section under Role-Based Security

Authorization in UI Components

Authorization in UI components is required if you need to:

If the user is not supposed to see certain piece of information, then the most secure option is to avoid passing this information to the UI components in the first place. Also note that you should set code access permissions on the UI assemblies if you do not want those assemblies (or the local components they) to access certain resources such as files.

Authorization in User Process Components

Because user process components manage data and control flow between user processes, perform authorization at this level if you need to:

Obviously the above restrictions need to be applied to UI elements. If the dialog box is the 'root' dialog box, then the appropriate menu entries need to be disabled or hidden. If the dialog box is the 'parent' from which other dialog boxes will be launches, then the dialog box must hide or disable UI elements for actions that users are not allowed to do.

Note that you can set authorization declaratively for user processes by adding PrincipalPermission attributes to the classes and methods that implement them. User process components are typically consumed from UI components so you can use code access security to restrict who is calling user process components.

Authorization in Business Components

Note the following guidelines:

Authorization in Service Agents / Service Interfaces

Because service agents are the gateways through which calls to external services are made, you should add authorization to these components whenever you want specific users or roles from accessing them. Note that external services may also implement their own authorization schemes.

Authorization in Data Access Components

Data access components are the last components that expose business functionality before the application data, so they should perform any needed fine-grained authorization before accessing data. Perform authorization at this level if you need to:

As usual, to perform authorization you can use .NET PrincipalPermission attribute if you are using Windows authentication or on .NET roles and attributes if you are not relying on Windows security context.

Authorization in Business Entity Components

You can enforce authorization in business entity components for proactive checks, but the final check should be performed business process components and data access components. You might also want to restrict access to business entity components from a code-access point. Doing so ensures that your business entities are only invoked by trusted code.

Secure Communication

In addition to authenticating and authorizing users, you must also ensure that inter-tier communication is secure - this ensures that the application is secure against attacks in which data is sniffed or tampered with while it is being transmitted. You have the following options for secure communications:

Digital signatures usually involve calculating a value (called hash) of the signed part of the message, encrypting the hash using the private key of the signer, and then including this encrypted hash in the message header. The receiver decrypts the signature using the public key of the signer and it compares the resulting hash with the one it calculates from the signed part of the message. If the hashes match, it means that the message has not been tampered with. If the do not match, the message has been corrupted or tampered with. For example, with XML Web Services, you can implement XML digital signatures in SOAP headers using the SignedXml class.

Securing a communication channel will affect performance. Therefore, only scope channel security to those areas where it is needed - such as securing specific URIs, specific ASP.NET pages, or sensitive business data.

Secure Communication in UI Components

UI components communicate only with the user. With Web Services, use SSL whenever sensitive data (credit card numbers, online banking, logon forms, etc.) are transmitted. Because user process components typically reside with UI components, there is no need to secure the channel between them.

Secure Communication in Service Agents and Service Interfaces

It is always a requirement for service agents to establish the appropriate channel security between itself and the invoked service. For example, if a service agent requires an SSL channel with an external service, then it is the service agent that should implement this functionality. This approach makes it easy to encapsulate secure communication mechanisms without affecting business components and workflows.

Secure Communication in Data Access Components

Data access components typically rely on data helper components to establish connections with the data store. Therefore, it is the responsibility of data helper components to establish secure communication with the data store. In particular, data helper components can encapsulate the following:

Profile Management

User profile is user information that the application can use to customize its look/behavior when used by that user. A user profile may include UI preferences (background color, font, etc.) and data about the user (region, address etc.) Profile information can be exposed as a collection by the Principal object. If profile information contains sensitive data, you may consider encrypting it.

Auditing

A general definition of auditing is the ability to track user and business activity in an application for security purposes. In fact, auditing can be thought of as secure logging. When implementing auditing solutions ensure that audit entries are tamper-proof or at least tamper-evident (achieved with digital signatures).  The auditing mechanism may have to use document signing, platform authentication, and code-access security to ensure that spurious entries can be logged by malicious code.

If the audited action needs to be associated with a specific user, the auditing interface may be exposed as a utility function or as a method of the application's Principal object.

Auditing in UI

Activities in UI are not usually audited (unless in financial trading applications). UI may want to audit certain global events like logging-in, logging-off, password changes, and all security exceptions. Because user process components represent user activities, it is not common to audit them.

Auditing in Business Components

Business components are prime candidates for auditing. You always want to know who performed key business activities and when were they performed. If you are auditing within the context of a transaction, the auditing component should also start a parallel transaction so that failures in the original transaction do not roll back the audit entry. 

Auditing in Data Access Components

Data access components are prime candidates for fine-grained auditing. Because data access components usually invoke stored procedures, you may also want to audit inside the data base. See Auditing SQL Server Activity article in MSDN.

Designing Operational Management Policies

Operational management policy is concerned with the ongoing data-to-day running of the application. Operational management policy covers issues such as exception management, monitoring, configuration, and service location as shown below:

The following sections are covered:

Exception Management

Exception management can be defined as: the process of throwing and catching exceptions, designing exception classes, flowing exception information across application components and layers, and publishing exception information.

In general, all applications must implement some kind of exception handling to catch runtime errors. Exceptions should be caught and resolved if possible. If an exception cannot be resolved, the application should display a meaningful message to the user and provide a way to log/publish the exception information for debugging purposes.

Exception Management has been discussed fully in the following sections:

The following sections discuss the various aspects of exception management:

Catching and Throwing Exceptions

The general advice on catching exceptions during a function call is to catch exceptions if your code can use the exception type and data to determine what to do next. It is advisable to catch exceptions at layer boundaries in order to wrap them with exception types that are relevant to the callers. You can throw a new exception and optionally preserve the original exception as an InnerException member of the new exception object you are throwing.

Designing Exception Classes

Exceptions classes should derive from ApplicationException class. Your application may need its own exception object model (i.e.,  exception hierarchy), where each business components might have a number of relevant exception classes specific to that business component. Within this exception hierarchy, you may then decide to enrich the exception by adding appropriate more data such as user name, IP address, .NET Framework version, and so on.

It is common now to derive two main branches of exceptions - business exceptions and technical exceptions. This design makes it easier to catch and publish the appropriate types of exceptions in different parts of the application.

Flowing Exception Information

Exceptions should always flow upstream, and therefore, need to be serializable to flow upstream across tiers. This is especially important as exceptions reach a UI or service agent boundary and you do not want to present the exception information as it happened. For example, what if the exception was due to an incorrect user name in a database connection string? You want to flow exception information across tiers (hence serializable) and at the same time modify the exception so that the user can understand it without exposing sensitive business or technical information.

Logging Exception Information

If an exception occurs, the appropriate staff must be notified. Technical exceptions should be go to technical support staff whereas business exceptions should go to managers and helpdesk staff. Each type of audience will want to know more about the environment in which the exception had occurred.

You should also publish relevant information for each audience through channels that communicate with the tools used by them. For example, technical exceptions going to technical support staff may published via WMI events, whereas business exceptions going to managers may be sent by email or a page/text message. In all cases, exceptions should be logged to a central repository like the event log or even a database.

Exception Management in UI

UI process components will need to handle exceptions flowing from business processes and data access components, and decide whether to:

UI components on the other hand should publish their UI exceptions to help isolate problems, especially in rich client applications.

Exception Management in Business Process Components

Handling exceptions in business components often requires catching exceptions and errors returned by business objects and encapsulating them into an exception that can be understood by the user. Business components need to handle exceptions coming from data access components. These include:

Obviously, business components should not hide these exceptions, but should propagate them to the caller. This could otherwise mislead business processes in terms of transactional state and make the user believe that certain operations were successful.

Business components should rains new exceptions when:

As for business entities, these may be called from the UI or from other business components. It is therefore, that you raise/propagate exceptions that can be consumed by both. 

Exception Management in Data Access Components

Data access components often handle two main types of exceptions:

If the running activities are transactional, then obviously all exceptions should abort the current transaction. Also note that handling exceptions in data access components often requires catching exceptions and errors returned by the underlying data store and mapping then to the exception schema used in the rest of the application. Data access components should propagate exceptions wrapping them in exception types that make sense to their clients. Wrapping exceptions in two main types (business and technical) improves exception handling structure and exception publishing logic for the potentially diverse callers.

The functionality to map data source exceptions (i.e., SqlException) to your .NET-based application exception schema should be implemented in the data access component. Performing mapping involves one or more of the following:

Monitoring

Monitoring is about instrumenting the application to give operations and support staff the ability to check application health, compliance with service-level agreements, and scaling/capacity management. See Monitoring in .NET Distributed Application Design in MSDN. 

There are the following types of monitoring:

These different questions can be answered by monitoring the right parts of the application. Also note that not all types of monitoring need to be active at all times. The following discuss different aspects of monitoring in a .NET distributed application:

Monitoring in User Process Components

Monitoring user process components can provide useful statistics to improve application UI design and efficiency. The following are some examples of what statistics can be provided by monitoring user process components:

Monitoring in Business Process Components

Health monitoring of business components and workflows is critical because it is where transaction outcome is known, and where data store problems are channeled. Most business-level monitoring is done in business layers

Monitoring in Data Access Components

Because data access components participate in transactions and talk to the database, they are important candidates for monitoring. Monitoring data access components allows you to track long-running queries, object lifetime duration, activity throughput, latency, memory, and other useful indicators. For example, whenever you connect to a database, monitor connection usage, connection pooling statistics, and connection security statistics. It can also be quite helpful to monitor transactional aborts because these can be very expensive to the application as a whole.

Configuration

Configurable applications should use configuration data stored in .NET configuration files at the user, machine, and application levels. Custom configuration data can be defined with any schema and accesses using the .NET ConfigurationSettings class. 

It is very important to consider configuration security - for example, most developers store database connection strings in clear text in .NET configuration files. You should restrict access to the proper operators and you may also consider digitally signing information to make sure that information has not been tampered with.

Configuration data can be stored in many places:

Accessing application configuration and metadata often results in performance hits, especially if the data is stored remotely. To prevent this, you can cache data in memory. When caching data in memory, issues relating to cache refresh to cash expiry need to be considered carefully. 

The requirements of various layers are as follows:

Metadata

The idea behind metadata is to provide the application with information about itself and its data to make the application more flexible as run-time conditions change. Designing the application to use metadata in certain places enables the application to adopt to changes without costly development/deployment changes. There are two main times when metadata can be used in an application:

The following sections illustrate potential uses of metadata:

Designing Communication Policies

Communications policy define how components in your application will communicate with each other. As shown below, communications policy deal with issues such as synchronicity, format, and protocol:

The following topics are covered:

Choosing the Correct Communication Model

Start by thinking carefully whether or not components need to communicate using messages or using a more tightly coupled and connected approach such as DCOM or .NET Remoting. While connected communication is easier to design and implement, it has limitations in terms of scalability, availability, and manageability.

Inter- and Intra-Application Communication

Inter-application and intra-application have the same scope as Inter-net and Intra-net; Inter refers to external communication while Intra refers to internal communication. Inter-application communication should be implemented using message-based communication such as SOAP-based Web Services or MSMQ. Intra-application communication may require a communication mechanism that provide high performance and specific capabilities such as transaction or security flow. In general, it is recommended that message-based communication be used whenever possible including communication between the different layers of a .NET distributed application.

Different requirements and constraints for inter-application and intra-applications communication will drive most technology decisions. In some cases, there might be no constraints on having tightly-coupled components that all communicate via .NET Remoting. In other cases, it may be useful to view the different tiers of an applications as services with the same loose-coupling found among unrelated services. The following figure illustrates these concepts

This diagram shows that the application's server-side components (1) are designed as a service that is accessed via a message bus (2). The presentation tier (3) uses same communication as other services (4). These services (4) potentially call other external services (6). Service agents (5) invoke other services (6) via the message bus. On the other hand, communication with data components (7) is implemented using other communication mechanisms. Viewing tiers as services may pose several design challenges:

If service integration is a small part of the application architecture, you may want to use Web Services for integration purposes only and use .NET Remoting for intra-application communication.  In the figure below, presentation, business and data tiers communicate with each other using .NET Remoting. The use of standards-based and message-based communication is left for integration purposes between service interfaces, service agents, and external services:

Message-Based communication

Message-based communication provides the best choice of communication for integration, especially when messages are asynchronous. Using asynchronous message-based communication offers the following advantages:

On the other hand, using asynchronous message-based communication offers the following disadvantages:

Scenarios for Message-Based communication

Design an interface to your application or service to be message-based when:

Synchronicity

It is common to think of message-based communication as an asynchronous model. However, message-based communication can also be encapsulated by a synchronous programming model (for example, using Web Services proxies generated by VisualStudio.Net) in which the clients waits for a message. Here the developer gains the advantages of message-based communication without having to deal with asynchronous programming complexities.

Technologies for Asynchronous Communication

A number of approaches can be used for asynchronous communications. Connected technologies such as .NET Remoting achieve asynchronicity using asynchronous delegates, whereas disconnected technologies such as MSMQ achieve asynchronicity using message-based communication. Of these approaches, queuing technologies offer the greatest advantages. For example, MSMQ provides a store-and-forward messaging transport for use in applications.

As an alternative to using queuing technologies, you can use proxies generated by XML Web Services in VisualStudio.NET. In this scenario, the proxy exposes a Begin<MethodName> and End<MethodName> for each method exposed by the Web Service. You can also implement asynchronous communication using .NET Remoting. See Using Asynchronous Calls in In-Depth Remoting section under .NET Remoting.

Technologies for Synchronous Communication

Answering the following questions will help you choose the proper synchronous communication technology based on your requirements:

  1. Do you need to flow transactions and/or Windows identity?
    If yes, use DCOM. Host your components in Enterprise Services to take advantage of transactions.
  2. Do you need broad reach?
    If yes, use XML Web Services with SOAP and HTTP. Move to question 4, otherwise move to question 3.
  3. Do you need to authenticate the caller?
    If you need authentication you need to have an IIS endpoint. Otherwise,  you can use any .NET Remoting channel hosted in any process.
  4. Do you need to implement a facade code to expose business functionality?
    If you need to wrap your business logic in an extra facade to perform validation, transformation, and may be even caching, you can use Web Services to easily implement functions callable by SOAP. Otherwise, you can expose types directly as Web Services.

For more information about deciding between XML Web Services and .NET Remoting, see .NET Remoting or Web Services article.

Recommendations

The application design should strive to use asynchronous communication as much as possible. In some cases however, it is reasonable for the client to expect a synchronous response. You can design your components such that they use asynchronous operations but they also provide a synchronous interface to callers. The basic design for achieving this is as follows:

Also note that the format in which you send and receive data and the schema of the data you exchange are important factors when designing the communication policy. The following factors influence format and schema:

References