Serialzation PREVIOUSLY: RFR: 8229773: Resolve permissions for code source URLs lazily

Peter Firmstone peter.firmstone at zeus.net.au
Sun Aug 18 02:22:20 UTC 2019


Thanks Sean,

You've gone to some trouble to answer my question, which demonstrates 
you have considered it.

I donate some time to help maintain Apache River, derived from Sun's 
Jini.  Once Jini depended on RMI, today, not so much, it still has some 
dependencies on some RMI interfaces, but doesn't utilise JRMP although 
it provides some backward compatibilty enable it.

But my point is, we heavily utilise java Serialization, and have an 
independant implementation of a subset of Java Serialization 
(originating from Apache Harmony).  We do this for security as we use an 
annotated serialization constructor.   Serial form is unchanged, we have 
Serializers for commonly used java library objects, for example, we have 
a "PermissionSerializer", but we don't have a 
"PermissionCollectionSerializer" or "PermissionsSerializer" (for 
java.security.Permissions).   Incidentally, we have found we do not need 
the ability to serialize circular object graphs.   Throwable is an 
object that has a circular object graph, but that circular object graph 
can be linked up after deserialization.

Permission implementing Serializable is probably not too much of a 
threat, as these objects are effectively immutable after lazy 
initialization.

ProtectionDomain calls java.security.Permissions::setReadOnly during 
it's construction.

ProtectionDomain::getPermissions returns internal 
java.security.Permissions.   If this is serialized, then the readOnly 
internal state can be written to as the internal object references are 
accessible from within the stream.

Admitedly, the attacker would already need to have some privilege, to 
have access to a ProtectionDomain, so it's a path of privilege 
escallation.  I'm not talking about gadget attacks and deserialization 
of untrusted data, I'm talking about breaking encapsulation.

Even though we are heavily dependant on Java Serialization, we are very 
careful when we implement it, and avoid implementing it when possible.   
Hindsight is 20:20, but given we are now seeing some Java SE backward 
compatibility breakages, perhaps it might be worth considering breaking 
serialization.  I don't mean we need to necessarily break object serial 
form, but making the Java serialization API explicit with subset of 
existing api features, that makes long term maintenace and security less 
of a burden and removing support for Serialization of some objects, 
where it is seldom used, perhaps using a JEP that requests developers to 
consider which library objects actually need to be serializable.

Something we do in our Java Serialization API is require that mutable 
deserialized objects are defensively copied during object construction 
(serial fields are deserialized before an object is constructed, the 
deserialized fields are accessible via a parameter passed in during 
construction.   We have tools that assist developers to check 
deserialized Java Collections contain the expected object types for 
example, so during object construction the developer has to replace the 
Collection with a new instance and copy the contents to the new 
Collection after checking the type of each object contained therein.   
Also we don't actually serialize Java Collections, we have standard 
serial forms for List, Set and Map, so these serial forms are equal, 
similar to the List, Set and Map contracts.  By doing this, Collections 
don't actually need to implement Serializable at all, as a Serializer 
becomes responsible for their serialization.   This also means that all 
Collections must be accessed by interfaces, rather than implementation 
classes, so the deserialization constructor, must defensively copy them 
into their preferred Collection instance.   It's a bit like dependency 
injection.

I know it would take time, and there would be some pain, but long term 
it would save a lot of maintenance developer time.

Regards,

Peter.

On 17/08/2019 12:50 AM, Sean Mullan wrote:
> On 8/15/19 8:18 PM, Peter Firmstone wrote:
>> Hi Roger,
>>
>> +1 for writeReplace
>>
>> Personally I'd like to see some security classes break backward 
>> compatibility and remove support for serialization as it allows 
>> someone to get references to internal objects, especially since these 
>> classes are cached by the JVM.  Which makes 
>> PermissionCollection.setReadOnly() very easy to bypass, by adding 
>> permissions to internal collections once you have a reference to them.
>>
>> Does anyone have any use cases for serializing these objects?
>>
>> These objects are easy to re-create by sending or recieving and 
>> parsing strings, because they are built from text based policy files, 
>> and when you do that, you are validating input, so I never did fully 
>> understand why they were made serializable.
>
> This is briefly explained on page 61 in the "Inside Java 2 Platform 
> Security" book [1]:
>
> "The Permission class implements two interfaces: java.security.Guard 
> and java.io.Serializable. For the latter, the intention is that 
> Permission objects may be transported to remote machines, such as via 
> Remote Method Invocation (RMI), and thus a Serializable representation 
> is useful."
>
> The Permission class was introduced in Java SE 1.2 so there were 
> different motivations back then :)
>
> --Sean
>
> [1] https://www.oracle.com/technetwork/java/javaee/index-141918.html




More information about the security-dev mailing list