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