Explicit Serialization API and Security

Peter Firmstone peter.firmstone at zeus.net.au
Sat Jan 3 20:29:25 UTC 2015


----- Original message -----
>
> As Brian points out, this scheme can only validate intra-class
> invariants. It can't validate class-against-subclass state.

Did he say that?

It's true that a superclass can't validate subclass state, it can't be expected to know much about it, but it can validate its own and prevent construction.  It can prevent extension too, ie be final, or require a permission to be extended.

 And, the
> finalize() method will be called anyway

The jvm makes no gaurantee a finalizer will run.

 - although this time with fully
> uninitialized instance (all fields default values). If this is safer,
> then alright.
>
> Is there anything in JLS that guarantees finalization for instances
> which fail construction or deserialization?

Not that I'm aware of.

Wouldn't it be better to
> "register" for finalization just those instances that complete their
> construction or deserialization normally? I'm just trying to understand
> why it is the way it is.

Perhaps that might be an option, someone who knows more about finalization might be able to help here.

In the early days, the sandbox and bytecode verifier were intended to make java secure, additional private methods were created as vulnerabilities were better understood.

I think a problem with Serialization is you have to establish trust before you can use it. 

It would be nice if there was an input validator like html servers use, to validate the stream before instantiating objects.  Eg array size check before array creation, type check before object instantiation and restrict creation to permitted classes, to a subset of what's available on the class path.

Techniques that prevent invalid object creation, are the most secure.

Circular links between untrusted classes still appear to require at least one object to be created before invarients can be checked and at least one mutated after.

Another option might be to require a Permission for Circular links, such that a thread may be run with a Subject that allows it for trusted connections and disallows it for untrusted serial data.

Regards,

Peter.

>
> Would something like this prevent Finalizer attacks?
>
> - leave finalization registration the way it is (at object allocation
> time). - provide internal API with which a previously registered object
> can be   de-registered
> - deserialization infrastructure de-registers the instances that fail
> deserialization
>
>

An alternative is to make an object unusable if it fails invarient checks, so all methods throw an exception.

> Regards, Peter
>
> >
> > A class can override the finalize method and make it final, but than
> > can cause objects to hang around longer than necessary.
> >
> > It's worth noting that all classes that implement Serializable have a
> > default no arg constructor, so presently don't have the option of
> > preventing object construction and typically have to clone mutable
> > referents after deserialization. Final fields only provide protection
> > for immutable referent objects.
> >
> > So this offers an improvement, at least for objects that don't have
> > circular links and it would allow them to retain compatibility with
> > their existing serial form.
> >
> > Cheers,
> >
> > Peter.
> >
> > For
> > > example, the above would be written as:
> > >
> > > class A {
> > > final int lower, upper;
> > > A(ReadSerial rs) {
> > > int l = rs.getInt("lower");
> > > int u = rs.getInt("upper");
> > > if (l > u) throw new IllegalArgumentException();
> > > lower = l;
> > > upper = u;
> > > }
> > > }
> > >
> > > class B extends A {
> > > final int cur;
> > > B(ReadSerial rs) {
> > > super(rs);
> > > int c = rs.getInt("cur");
> > > if (c < lower || c > upper) throw new
> > > IllegalArgumentException();                               cur = c;
> > > }
> > > }
> > >
> > >
> > > >
> > > > 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
> > >
> > > This is tricky, yes. In general, the graph of objects has to be
> > > linked somehow gradually where links are established to
> > > half-initialized objects. So there would have to be a special
> > > post-deserialization call-back over the deserialized objects just
> > > for checking the invariants. But what to do with the instances that
> > > "escape" during the process? This is why explicit (de)serialization
> > > is tricky - it allows arbitrary user code to be executed during the
> > > construction of the
> > object
> > > graph.
> > >
> > > Perhaps we just need some kind of declarative prescription of
> > serialized
> > > state and mapping to fields of objects in the form of annotations or
> > > such (see what JPA is doing in this field). Combined with
> > > post-deserialization invariant-checking call-back method perhaps.
> > >
> > > Regards, Peter.



More information about the core-libs-dev mailing list