Automatic Deserialization in .NET Remoting
Remoting systems that rely on run-time type validation must deserialize a remote stream to begin using it, and an unauthorized client could try to exploit the moment of deserialization. To help protect against this type of attack, .NET remoting provides two levels of automatic deserialization, Low and Full. Low (the default value) protects against deserialization attacks by deserializing only the types associated with the most basic remoting functionality, such as automatic deserialization of remoting infrastructure types, a limited set of system-implemented types, and a basic set of custom types. The Full deserialization level supports automatic deserialization of all types that remoting supports in all situations.
CAUTION Do not assume that controlling deserialization is the only security your application needs. In distributed applications, even a high degree of control over serialization will not prevent unauthorized clients from intercepting the communication and using it in some way, even if that is merely showing the data to others. Therefore, although the Low deserialization level provides some protection against certain types of attack based on automatic deserialization, you must still evaluate whether to use authentication and encryption to help protect your data. For details, see Security.
The following lists describe the .NET remoting deserialization levels:
- Low (default level)
The default deserialization level in .NET remoting supports deserialization of the following types:
- Remoting infrastructure objects. These are the types needed to make remoting work at a basic level.
- Primitive types, and reference and value types that are composed of primitive types.
- Reference and value types that are marked with the SerializableAttribute attribute but do not implement the ISerializable interface.
- System-provided types that implement ISerializable and make no other demands outside of serialization.
- System-provided types that implement ISerializable or are marked with the SerializableAttribute and live in an assembly that is not marked with the AllowPartiallyTrustedCallersAttribute attribute.
- Custom types that have strong names and live in an assembly that is not marked with the AllowPartiallyTrustedCallersAttribute attribute.
- Custom types that implement ISerializable and make no other demands outside of serialization.
- Types that implement the ILease interface and are not MarshalByRefObject objects.
- ObjRef objects used for activation (to support client-activated objects); that is, the client can deserialize the returned ObjRef but the server cannot.
The Full deserialization level in .NET remoting supports all other scenarios, including the deserialization of the following additional types:
- ObjRef objects passed as parameters.
- Objects that implement the ISponsor interface.
- Objects that are inserted between the proxy and client pipeline by the IContributeEnvoySink interface.
If your application needs to use remoting features that are available only at the Full deserialization level, you must provide the type of authentication and the level of encryption necessary to protect any resources that might be at risk by using these advanced features in remote scenarios.
You can set the deserialization level programmatically or by using an application configuration file.
Setting the Deserialization Level Programmatically
To set the deserialization level programmatically, pass the following property to the SoapServerFormatterSinkProvider object or BinaryServerFormatterSinkProvider object on creation. The remoting system will then set the value on the formatter when it is inserted into the sink chain. The following example demonstrates how to set the deserialization level to Full in a host application domain.
// Creating a custom formatter for a TcpChannel sink chain.
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = TypeFilterLevel.Full;
// Creating the IDictionary to set the port on the channel instance.
IDictionary props = new Hashtable();
props["port"] = 8085;
// Pass the properties for the port setting and the server provider in the server chain argument. (Client remains null here.)
TcpChannel chan = new TcpChannel(props, null, provider);
' Creating a custom formatter for your TcpChannel sink chain.
Dim provider As New BinaryServerFormatterSinkProvider()
provider.TypeFilterLevel = TypeFilterLevel.Full
' Creating the IDictionary to set the port on the channel instance.
IDictionary props = new Hashtable()
props("port") = 8085
' Pass the properties for the port setting and the server provider in the server chain argument. (Client remains null here.)
Dim chan As New TcpChannel(props, null, provider)
Setting the Deserialization Level Using an Application Configuration File
To use a configuration file to set the deserialization level, you must explicitly specify the typeFilterLevel attribute of the <formatter> element. Although this is typically done on the server side, you must also specify this attribute to control the deserialization level for any channel on the client registered to listen for a callback. The following example explicitly sets the deserialization level to Low for both the SoapFormatter and BinaryFormatter in the application domain.
<provider ref="wsdl" />
<formatter ref="soap" typeFilterLevel="Low" />
<formatter ref="binary" typeFilterLevel="Low" />