In general, applications that use .NET remoting have a more complex set of security issues than local applications.
Securing distributed applications poses a problem that is difficult to overcome without resorting to measures that hamper performance. If one end of communication is listening for an invocation, any unauthorized client that knows about the listening endpoint may attempt to pass some serialized information hoping that it can get the information deserialized on the other end and invoked in some way. Only by mutually authenticating and then encrypting the content can you be certain that the communication is occurring between components with a high degree of trust. As a result, you should evaluate the design of your remoting application with respect to your security requirements first, and then with respect to performance requirements. The degree to which you expose data and endpoints without these types of security precautions should be the degree to which you require data integrity for your application and the level of investment you have put into your data.
Remoting delegates illustrates the problem. Because delegates can wrap the type information of static methods (which will never execute remotely), your server applications should always declare a custom delegate type that takes custom parameters that, taken together, will never match a static method that is callable on the server computer. Never allow a client to define and pass to your application any type that your server might intentionally or unintentionally deserialize.
The important part of designing secure, distributed applications that use the .NET remoting infrastructure is to be sure that you know which level of security you want, and where you want it. This section describes the various approaches to security based on certain design decisions. Not all scenarios are addressed here, but these topics are a good starting point for making decisions.
Code Access Security
Code access security controls the access that executable code has to resources and operations based on the security policy set by the administrator of the computer. However, because code access security does not walk the stack across a remote connection, developers of remoting applications should clearly understand that the remoting infrastructure requires full trust to execute on either the client or the server.
CAUTION You should never try to create a remotable wrapper for an AppDomain object. If you do so, you may be able to publish a reference to that AppDomain remotely, which exposes the AppDomain.CreateInstance method (or other methods) remotely, effectively destroying any code access security for that AppDomain. Unauthorized clients connecting to the remoted AppDomain may be able to obtain access to any resource that the AppDomain itself can access. In fact, you should not do this for any type that extends MarshalByRefObject and that implements methods that could be used by unauthorized clients to bypass the security system in any way.
More generally, several system types extend MarshalByRefObject but do security checks at run time to prevent anything outside the application domain from actually invoking an object of that type remotely. AppDomain and System.Windows.Forms.Form are two examples of this. It would be easy to think that you can extend MarshalByRefObject and obtain a reference remotely, but with these special types that is not the case. It may be tempting to wrap the in-process reference with another remotable type, but doing so unintentionally circumvents code access security and should never be done.
Security Considerations in Remoting Applications
In general, there are two areas of security that you might need to address in your distributed application, depending on your particular scenario. You secure the communication channel and the message itself, or you secure the application against improper use, or both to some degree.
Typically, securing the communication channel has meant encrypting the content of the message on one side of the stream and decrypting it on another, encrypting the channel itself, or both. The content of the message might require an integrity check, to make sure that no one has tampered with it. The identity of the client or the server (or both) might also need to be confirmed.
You can help protect the application against unauthorized use either by making sure the user has the permission to use the application in the first place or by logging the user's behavior to reconstruct use patterns afterward.
Designing Security in Remoting
There are two main questions you need to answer to design a secure, easy-to-build application:
- What channels are available?
- What is the user authentication and authorization model for the server?
If you have a choice between using an HttpChannel object and an TcpChannel object, it is recommended that you use the HttpChannel and host your remote objects in Internet Information Services (IIS), no matter what the user authentication and authorization models are. IIS hosting provides support for wire-level protection using Secure Sockets Layer (SSL) and authentication using Integrated Windows Authentication (formerly NTLM authentication) or Kerberos.
The TcpChannel, as an implementation of the Transmission Control Protocol (TCP), does not have default support for some of the robust authentication standards that the HTTP standard has. Within an environment that has wire-level protection (such as IPSec), the high-speed TcpChannel can be used, but it is not recommended over the Internet or an unencrypted intranet.
CAUTION .NET remoting does not do authentication or encryption by default. Therefore, it is recommended that you take all necessary steps to make certain of the identity of clients or servers before interacting with them remotely. Because .NET remoting applications require FullTrust permissions to execute, if a unauthorized client were granted access on your server, the client could execute code as though it were fully trusted. Always authenticate your endpoints and encrypt the communication streams, either by hosting your remoted types in IIS or by building a custom channel sink pair to do this work.
The user authentication and authorization model for the server might vary widely, but hosting your remote objects in IIS supports the most complex solutions. They require little coding, and you have default support on the server for discovering the WindowsPrincipal object or GenericPrincipal object of the client. This is convenient when you need to impersonate the client to perform some function on the user's behalf. For details, see Impersonating and Reverting.
GenericPrincipal objects represent any user authorization scheme independent of Windows domains. As a result, these objects can be extended to work with user databases and to interoperate with other platforms.
.NET Remoting Overview | HttpChannel Web Security | Role-Based Security in Managed Applications | Code Access Security | RemotingConfiguration | ChannelServices | Context | MethodCall | RemotingServices