river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Michal Kleczek <michal.klec...@xpro.biz>
Subject Re: [jira] Created: (RIVER-362) Denial of Service during unmarshalling of smart proxy's
Date Thu, 28 Oct 2010 09:40:11 GMT
On Thursday 28 of October 2010 10:36:38 Peter Firmstone wrote:
> Ok Interesting, anyone implementing a Service should be quite capable of
> implementing equals, we should then specify that equals and hashcode
> methods should be implemented for ProxyTrust.
> For my benefit can you go over the process of how your new code works?
> I'm interested in the choices you've made & why.

Several choices were made because:
1. I wanted to reuse as much as possible from existing River
2. I wanted to have a working prototype fast :)

1. The main idea is to have annotations as objects that could be verified using 
standard River proxy verification facilities. To be honest the idea of having 
Module interface that enables plugging different classloading mechanisms is 
something completely optional.
2. For the client the basic scenario is:
a) The client gets a serialized object
b) When it is deserialized annotations (Modules) are read and "installed"
c) Installing a Module means:
c1) checking if it was already installed
c2) if not - prepare it using VerifyingProxyPreparer (I've choosen not to 
place any InvocationConstraints on Modules - I don't think it is necessary)
d) after a Module is installed it is used to load classes
3. There are several places in River that depend on annotations being Strings 
provided by RMIClassLoader. The most important places are
a) Discovery
b) Reggie implementation
c) ProxyTrustVerifier
Since I did not want to modify this code I had to implement RMIClassLoaderSpi 
so that it would provide serialized Modules as Strings. I've choosen to simply 
serialize them to byte arrays and Base64 encode them.
4. There are two important Module implementations available:
a) DefaultRmiModule
b) ProxyTrustModule
DefaultRmiModule can be trusted by the client without contacting any service - 
it uses RequireDlPermissionClassProvider to load classes.
ProxyTrustModule on the other hand uses a simple PreferredClassProvider to 
load classes. It is a smart proxy that implements getProxyTrustIterator() so 
that it can be verified by ProxyTrustVerifier.

On the server before we can annotate our objects with modules we have to 
register a Module that will be used as annotation.
If the server does not register any Module - DefaultRmiModule is going to be 
used as annotation.
The server can register a ProxyTrustModule as annotation - to do that it first 
must export an object that can be contacted to obtain a Module verifier.
In other words - a service must either:
a) export two ProxyTrusts (one for Modules and another one for the service 
b) its ProxyTrust must provide a verifier that is able to verify both a Module 
and a service proxy

To make it possible to use my code with existing services without modifying 
them I've decided to implement a special ModuleExporter which will override 
the service ServerProxyTrust implementation so that getProxyVerifier will 
return a Verifier capable of verifying both a Module and the service proxy.
This verifier works as follows:
1. Check if an object being verified is a Module.
2. If so - delegate to a module verifier
3. If not it means we're verifying a service proxy so delegate to a default 
The problem is though that when this verifier is deserialized the module that 
is capable of loading the service proxy verifier is not yet installed (the 
client got this verifier to verify a Module before it can load any classes). 
That's why I called it LazyCompositeVerifier - the default verifier is not 
deserialized until it is actually needed.

The only problem left is that every time a client gets a service proxy it will 
issue a remote call twice to get a verifier: first to get a verifier for a Module 
and then to get a verifier for a service proxy. But it is going to be the same 
verifier!!! So I've decided to implement a CachingProxyTrust that
1) can be trusted by the client without the need to issue any remote call (so 
we need a CachingProxyTrustVerifier configured on the client)
2) Will cache a verifier it obtains from its delegate

The problem with CachingProxyTrust is that it has to be used by:
a) a Module
b) a service proxy
That's why we need OverrideProxy - it is returned from ModuleExporter to the 
service so that the service is unaware of the CachingProxyTrust but still can 
use it to obtain its verifier. To trust OverrideProxy the client has to have 
OverrideProxyVerifier configured locally.

I hope I clarified everything a little bit...


View raw message