Explicit Serialization API and Security

Peter Firmstone peter.firmstone at zeus.net.au
Tue Jan 13 00:51:09 UTC 2015


----- Original message ----- 
> On 10/01/15 07:00, Peter Firmstone wrote: 
> > Again, thank you all for engaging in discussion of this very difficult 
> > topic. 
> > 
> > While we can't presently check intra object dependencies during 
> > deserialization with readObject(), the examples I provide can do this. 
> 
> I have replied to Davids mail with a small change to GetField ( added 
> superTypeFields() ) to return the deserialized supertypes fields. This 
> gives subtypes the ability to check values of the supertypes persistent 
> state. 

Unfortunately this breaks encapsulation, a class is then locked into
using that serial form as public api forever.


> 
> As with your original proposal, it is limited to the persistent state as 
> read off the stream, and not the transient state, but I think it gets us 
> most of the way there. 
> 
> In your original proposal, it looks quite cumbersome to hook up the 
> static validator method in the constructor hierarchy ( as it is to do 
> this with standard constructors too ). It also relies on the fact that 
> the subtype has to create an instance of the supertype. I just wonder if 
> we can push on the alternative static validator proposal to come up with 
> something a but more attractive ( maybe not! ). 

Before proposing the constructor, I had considered a static validator 
method, with the following limitations:

    * A static method invariant check, while simple, cannot accommodate
      intra object invariants in class inheritance hierarchies without
      breaking encapsulation and allowing child classes to examine stream
      content.

    * When we break encapsulation, complexity of implementing Serializable
      safely increases; how to evolve serial form without breaking
      compatibility.

    * An Object under construction, usually copies mutable parameters 
      before checking invariants, how can we guarantee that these objects
      are not shared and haven't mutated between the time the invariants
      are checked and when fields are set by reflection after
      construction?
	
I'd also considered a static factory method:

    * It offers maximum flexibility for evolution; it can return objects
      of any class it likes.
    * Lacks the ability to recreate inherited private state, without
      breaking encapsulation.
    * Issues establishing intra object dependencies in inheritance
      hierarchies.
      

Advantages that led me to propose the use of a constructor:

    * If existing constructors throw an exception when invariants
      haven't been satisfied, best practise dictates they must
      do so prior to calling Object's super class constructor to avoid 
      finalizer attacks; static validation methods should already exist,
      if not the class should be refactored anyway, whether it implements
      Serializable or not.
    * Improved code reuse; invariant validation code is shared with
      other constructors.
    * Ability to satisfy complex intra object invariants in class
      inheritance heirarchies without breaking encapsulation.
    * Although it appears complex at first glance, once learnt, 
      it's easily proven, preserves encapsulation and is easy to 
      implement and test.
    * No serial form lock in, encapsulation has not been broken.
      Only the implementing class knows and uses the field names and types 
      directly. 

It just seems like the best compromise, it's not perfect, is has less flaws.



> 
> Have you seen the changes I proposing for failure atomicity, preliminary 
> webrev 
>        http://cr.openjdk.java.net/~chegar/failureAtomicity/ 
> 
>        .. and I think we can go further than this, creating the containing 
> object lazily, if there are no readObjectXXX methods in the hierarchy. 
> 
> 

Yes, but need some more time to absorb it, before commenting.

Regards,

Peter.


More information about the core-libs-dev mailing list