Explicit Serialization API and Security

Brian Goetz brian.goetz at oracle.com
Fri Jan 2 22:53:01 UTC 2015


Overall the direction seems promising.  Poking at it a bit...

  - ReadSerial methods are caller-sensitive and only show a class a view 
of its own fields.
  - Invariant checking is separate from deserialization, and does not 
seem entirely built-in -- subclass constructors seem responsible for 
asking parents to do validity-checking?
  - I don't see how this invariant-checking mechanism can enforce 
invariants between superclass fields and subclass fields.  For example:

class A {
     int lower, upper;  // invariant: lower <= upper
}

class B extends A {
     int cur;  // invariant: lower <= cur <= upper
}

To check such an invariant, the serialization library would have to 
construct the object (in a potentially bad state), invoke the checker at 
each layer, and then fail deserialization if any checker said no.  But, 
an evil checker could still squirrel away a reference under the carpet.

Another challenge in invariant checking is circular data structures.  If 
you have two objects:

class Brother {
     final Brother brother;
}

that refer to each other, an invariant you might want to check after 
deserialization is that
   this.brother.brother == this

Obviously you have to patch one or the other instance after construction 
to retain the circular references; at what point do you do invariant 
checking?

On 1/1/2015 7:43 AM, Peter Firmstone wrote:
> Subclass example:
>
> class SubFoo extends BaseFoo {
>
> public static ReadSerial check(ReadSerial rs){
> if (rs.getInt("y") > 128) throw Exception("too big");
> return rs;
> }
>
> private final int y;
>
> public SubFoo( int x , int y) {
> super(x);
> this.y = y;
> }
>
> public SubFoo( ReadSerial rs ){
> super(BaseFoo.check(check(rs)));
> // SubFoo can't get at BaseFoo's rs.getInt("x"),
> // it's visible only to BaseFoo. Instead SubFoo would get
> // the default int value of 0. Just in case both classes have
> // private fields named "x".
> // ReadSerial is caller sensitive.
> this.y = rs.getInt("y");
> }
> }
>
> Classes in the heirarchy can provide a static method that throws an
> exception to check invarients while preventing a finaliser attack. We'd
> want to check invarients for other constructors also, but for berevity...
>
> Eg:
>
> class BaseFoo implements Serializable{
>
> public static ReadSerial check(ReadSerial rs) throws Exception
> {
> if (rs.getInt("x") < 1)
> throw IllegalArgumentException("message");
> return rs;
> }
> ....
>
>
> Sent from my Nokia N900.
>
> ----- Original message -----
>  > So, if I understand this correctly, the way this would get used is:
>  >
>  > class BaseFoo implements Serializable {
>  >          private final int x;
>  >
>  >          public BaseFoo(ReadSerial rs) {
>  >                  this(rs.getInt("x"));
>  >          }
>  >
>  >          public BaseFoo(int x) {
>  >                  this.x = x;
>  >          }
>  > }
>  >
>  > Right?
>  >
>  > What happens with subclasses?  I think then I need an extra RS arg in my
>  > constructors:
>  >
>  > class SubFoo extends BaseFoo {
>  >          private final int y;
>  >
>  >          public SubFoo(ReadSerial rs) {
>  >                  this(rs.getInt("y"));
>  >          }
>  >
>  >          public BaseFoo(ReadSerial rs, int y) {
>  >                  super(rs);
>  >                  this.y = y;
>  >          }
>  > }
>  >
>  > Is this what you envision?
>  >
>  >
>  >
>  >
>  >
>  > On 12/27/2014 8:03 PM, Peter Firmstone wrote:
>  > > Is there any interest in developing an explicit API for
> Serialization?:
>  > >
>  > > 1. Use a public constructor signature with a single argument,
>  > > ReadSerialParameters (read only, writable only by the
>  > > serialization framework) to recreate objects, subclasses (when
>  > > permitted) call this first from their own constructor, they have
>  > > an identical constructor signature.  ReadSerialParameters that are
>  > > null may contain a circular reference and will be available after
>  > > construction, see #3 below.
>  > > 2. Use a factory method (defined by an interface) with one parameter,
>  > > WriteSerialParameters (write only, readable only by the
>  > > serialization framework), this method can be overridden by
>  > > subclasses (when permitted)
>  > > 3. For circular links, a public method (defined by an interface) that
>  > > accepts one argument, ReadSerialParameters, this method is called
>  > > after the constructor completes, subclasses overriding this should
>  > > call the superclass method.  If this method is not called, an
>  > > implementation, if known to possibly contain circular links,
>  > > should check it has been fully initialized in each object method
>  > > called.
>  > > 4. Retains compatibility with current serialization stream format.
>  > > 5. Each serial field has a name, calling class and object reference,
>  > > similar to explicitly declaring "private static final
>  > > ObjectStreamField[] serialPersistentFields ".
>  > >
>  > > Benefits:
>  > >
>  > > 1. An object's internal form is not publicised.
>  > > 2. Each class in an object's heirarchy can use a static method to
>  > > check invarients and throw an exception, prior to
>  > > java.lang.Object's constructor being called, preventing
>  > > construction and avoiding finalizer attacks.
>  > > 3. Final field friendly.
>  > > 4. Compatible with existing serial form.
>  > > 5. Flexible serial form evolution.
>  > > 6. All methods are public and explicitly defined.
>  > > 7. All class ProtectionDomain's exist in the current execution
>  > > context, allowing an object to throw a SecurityException before
>  > > construction.
>  > > 8. Less susceptible to deserialization attacks.
>  > >
>  > > Problems:
>  > >
>  > > 1. Implementations cannot be package private or private.  Implicit
>  > > serialization publicises internal form, any thoughts?
>  > >
>  > > Recommendations:
>  > >
>  > > 1. Create a security check in the serialization framework for
>  > > implicit serialization, allowing administrators to reduce their
>  > > deserialization attack surface.
>  > > 2. For improved security, disallow classes implementing explicit
>  > > serialization from having static state and static initializer
>  > > blocks, only allow static methods, this would require complier and
>  > > verifier changes.
>  > > 3. Alternative to #2, allow final static fields, but don't allow
>  > > static initializer blocks or mutable static fields, similar to
>  > > interfaces.
>  > >
>  > > Penny for your thoughts?
>  > >
>  > > Regards,
>  > >
>  > > Peter Firmstone.
>



More information about the core-libs-dev mailing list