Description
Some remoting technologies use BinaryFormatter
to serialize Exception
instances across security boundaries, which puts them out of SDL compliance and potentially exposes consumers to security vulnerabilities. The current recommended way to serialize exception information safely is to call ToString
on the exception instance, then transmit the resulting string across the wire. However, this does not create useful object models for consuming applications, as they can't interact with a simple string like they can a rich exception instance (accessing properties, using try / catch, etc.).
In an ideal world, an exception serialization tech would have the following characteristics:
- The proper
Exception
-derived type will be instantiated after deserialization. - The human-readable message and stack trace are preserved.
- The inner exceptions are preserved.
- Vital information about the exception is preserved. This is normally information passed to the Exception ctor and exposed via properties, such as the argument name provided to an
ArgumentOutOfRangeException
.
To maintain SDL compliance and work with our linker technology, we'd need to enforce a few extra behaviors:
- The payload cannot be the sole arbiter of type information. The deserializer needs to provide an allow list of legal
Exception
-derived types, and the payload cannot attempt to instantiate types outside that allowed list - The deserializer tech must go through normal instance validation and type safety checks, normally performed by the exception's ctor. This disallows using the existing
SerializationInfo
/StreamingContext
infrastructure. - Cyclic or deeply-nested object graphs must not be constructed. This also disallows using the existing
SerializationInfo
/StreamingContext
infrastructure.
It's possible that the deserialization tech would need to include special-case handling of each allowed Exception
-derived type in order to fulfill these requirements. Perhaps this could be simplified by understanding canonical patterns like .ctor(string message, Exception innerException)
. But we'll cross that bridge when we come to it.