Explicit Serialization API and Security
David M. Lloyd
david.lloyd at redhat.com
Thu Jan 8 15:32:26 UTC 2015
On 01/08/2015 02:32 AM, Peter Firmstone wrote:
> Thank you all for participating in this discussion.
> Initially a constructor signature for deserialization was proposed to
> enforce invariants and encapsulation, however there appears to be
> interest in using alternative methods, although they appear to be
> improvements over the status quo, I'm having trouble working out how to:
> * Enforce intra class invariants with alternate proposals without
> breaking encapsulation.
> * How the static method proposal can be used to replace final fields
> referents without needing to implement readObject().
> * And how the alternative GetFields readObject() implementation can
> enforce invariants and prevent finalizer attack, while also
> allowing subclassing?
> What started me down this path, is our project (Apache River) is heavily
> dependant on Serialization, I wanted to create a secure
> ObjectInputStream subclass that restricted deserialized classes to those
> I had audited. My aim was to allow deserialization to enforce security
> using verification, similar to how an http server verifies its input.
Now we're getting down to brass tacks. :-)
Maybe I missed this part of the discussion, but can you elaborate on why
ObjectInputValidation is inadequate for validating intra-class
invariants? I was thinking this is really the only way to effectively
achieve intra-class validation, because (barring complex graph traversal
algorithms) there isn't really any better way to guarantee that any
given subgraph of the object graph is actually fully initialized.
As far as replacing final fields, I think the seed of the best idea came
from Chris Hegarty - the problem isn't the readObject() method, the
problem is that there's no way to initialize your final fields if you
use it. By adding a "defaultReadFields()" (name not important) method
like he proposes, you can validate your single class. But I don't see
any reason why this couldn't be taken another step farther, and allow
the readObject method to actually change, add, and remove fields from
its internal map before doing so. This would allow readObject to
arbitrarily transform its content, and assign to final fields, while
only minimally changing the API and implementation.
> Unfortunately before I can achieve the goal of secure deserialization,
> there's a denial of service issue in ObjectInputStream: I'd also like to
> propose a system property, to allow limiting the size of arrays, created
> during deserialization. Presently I can craft an inputstream to take
> down the JVM, if I can do it, so can an attacker, I'd like to get that
> fixed if possible.
I agree this would be a very good (and easy to implement) idea. You can
limit the underlying stream but that does you no good if the attacker
can cause the construction of any number of very large objects before
the end of stream is hit.
I wonder if this could be as simple as adding a protected method on
ObjectInputStream in the vein of:
protected boolean validateArrayCreation(Class<?> elementType, int
Or elementType could be arrayType; I don't think it matters too much.
Method returns false and InvalidObjectException is thrown.
Implementations could do a simple global max array size, different max
sizes by primitive vs ref, different by type, or even have a "budget" of
heap and use a combination of this method and overridden resovleClass()
to create a rough estimate of memory usage, failing at a heuristic
> I've attached a text file that contains three classes using the original
> proposed serial constructor, A, B and C which have intra class
> invariants that must be satiisfied. C also contains a circular link and
> implements an interface called Circular, the Serialization framework
> calls it after construction to provide access to fields with circular
> links. Can the other proposals provide similar safety?
> 1. The class with the circular link is final and every method checks
> if invariants are satisfied.
> 2. The method with @SerialConstructor annotation, is the only
> constructor called by the serialization frame work, other than the
> Circular interface method, there are no other methods that need to
> be implemented.
> 3. Encapsulation is preserved, classes have full control over their
> invariants, their internal implementation and what's serialized.
I was previously firmly of the opinion that a serialization constructor
is the best way to accomplish this, but this discussion thread has at
least given me quite some doubt if not outright changed my mind, though
I think there's still an unanswered question regarding validation (above).
If nothing else, this discussion has yielded some good ideas for
enhancements to JBoss Marshalling. :-)
More information about the core-libs-dev