Hi Michal,Sorry for taking time to respond, I've been busy and am still digesting the code.
Michal Kleczek wrote:
In my code there is a simple hack to force creating a different ClassLoader for each unique Module - before calling to a delegate RMIClassProviderSpi I set a TCCL to a new ClassLoader that is unique to the Module. (That is also the reason I had to provide a slightly modified version of BasicJeriTrustVerifier so that not the proxy ClassLoader but also its parent are verified)Ok I see your point, we should be using service proxy identity, not the Subject. A server might use a number of subjects. Since not all proxy's are services, would it be better to use the BasicObjectEndpoint identity.See AbstractRmiModule for details.Module uniqueness: two Modules are considered the same iff their equals returns true.In case of ProxyTrustModule (which is the most interesting) - two ProxyTrustModules are equal when their codebases are equal and their ProxyTrusts are equal. so for two different services - each providing its own ProxyTrust for Modules - we create two different ClassLoaders regardless of the codebases. (This is not based on Subject but on service proxy identity) Basing it on Subject would be a little tricky IMHO because actual service Principals are dependent on what the client requires.
ProxyTrust, doesn't by default implement equals or hashcode, if the client is handed a reference to a remote object, that is a smart proxy, from another client, it could end up with two separate instances if ProxyTrust uses the default Object equals implementation.
So thinking about it a little more, perhaps we could use the Uuid of the BasicObjectEndpoint?
Doing so has a significant drawback, limiting sharing of common bytecode.If we weren't worried about security, for efficiency reasons we'd keep all services with identical code in the same ClassLoader, or name space, the security risk is the service proxy object of one provider could communicate with another with different privileges using class variables.
Another reason for not using the Subject, even if there was no immediate security risk due to sharing of class variables, the services within the ProtectionDomain must have identical permissions, under identical circumstances, but because all proxy's cannot be discovered and verified at the same time, this would not be easily possible.
So it might be wise to remain on the conservative side and designate a ClassLoader for each unique remote object, and cache codebases, to reduce downloading.
Regards, Peter.
We can sign codebases using SignedRmiModule which - beside codebase - carries signature information with it and can be verified locally by SignedRmiModuleVerifier (not yet finished). I also thought about delegating signature verification work to a (remote) service that would be carried by SignedRmiModule and verified for trust before used by the client to verify the actual signature.The whole design was based on Jini 2.1 so no dynamic CodeBase grants are necessary.Regards, Michal On Tuesday 19 of October 2010 03:10:50 Peter Firmstone wrote:Michal, You compose an incredible amount of code in a very short time, I haven't yet digested it. I'm still trying to figure out how a Service proxy's namespace can be restricted to a single Subject (the Service authenticates itself with). To avoid security vulnerabilities, caused by shared class state. Classes within a ClassLoader belonging to a particular Service should have no visibility outside their ClassLoader, external classes should only be able to interact via Service API, they shouldn't be able to create objects using constructors from within the service proxy's namespace. The Service proxy needs to have isolated visibility. Objects within the proxy's private namespace are constructed during deserialization. We could require that a proxy codebase must be signed, we could also require that the Subject, when it authenticates has the same Certificate as the codebase. Since Certificate's have chains of trust, which can grow longer, it would only be the first Certificate in each Certificate[] array (Subject and CodeSource) that would be checked. Using Codebase Certificate's has an advantage over message digests because the implementation can change. After a smart proxy has been unmarshalled, if it is discovered that the Certificates don't match, this indicates the proxy has been downloaded into the wrong namespace, this proxy can be safely discarded. Cheers, Peter. Michal Kleczek wrote:Folks, I've managed to create a prototype implementation of the idea of annotating classes with Modules. Working on this allowed me to learn quite a lot about inner workings of River - the original implementation that I've presented before had to be modified (not saying it had to be fixed :) ) but the main idea stayed the same. This time I think it really covers more use cases. Shortly: 1. We allow annotating classes with Modules. A Module is an object responsible for loading classes. 2. There is a new RMIClassLoaderSpi implementation which I called ModuleClassProvider 3. ModuleClassProvider manages installed Modules 4. It also can load classes based on String annotations which are expected to be either a) serialized and Base64 encoded Module - the Module is deserialized and handled as any other Module annotation b) an old style list of URLs - class loading is delegated to RequireDlPermProvider - in other words we either load classes from Modules (which are verified for trust before use) or from URLs but then we require appropriate DownloadPermissions Attached is a multi-module maven project. The modules are: 1. secure-marshall-stream (which is the implementation of all this + some not yet finished additional code) 2. jsk-module-platform which contains modified Jini classes so that it all works with existing Jini services (to be honest only ClassLoading really needed to change. MarshalInputStream/MarshalOutputStream/MarshalledInstance are changed only to avoid having serialized and Base64 encoded Modules as annotations To run it you need to put jsk-module-platform before jsk-platform on the classpath (and of course add secure-marshall-stream as well) Existing services can be exported with a ModuleExporter: private serviceILFactory = new ProxyTrustILFactory(serviceConstraints, RegistrarPermission.class);private moduleTrustILFactory =new ModuleTrustILFactory(serviceConstraints, null);serverExporter = new ModuleExporter(newBasicJeriExporter(serviceEndpoint, serviceILFactory), new BasicJeriExporter(serviceEndpoint, moduleTrustILFactory)); I've done some basic scenario testing which was running Reggie and Service Browser installed by Jini 2.1 installer. Both Browser and Reggie policies did not grant any DownloadPermissions. When exported with BasicJeriExporter lookup of ServiceRegistrar by the Browser failed with missing DownloadPermission. When exported with ModuleExporter both Reggie and Browser used ProxyTrustVerifier to verifify Modules. Note - this is strictly a prototype - no comments / junit tests / code reviews and no real testing. If you have any questions / comments - you're very welcome. Michal On Monday 18 of October 2010 03:08:38 Peter Firmstone wrote:Notes for fix: DownloadPermission protects against unauthenticated downloads ClassLoadingPermission - new Permission to protect against unauthenticated Class loading. Issues we're addressing in the DOS hole: * Eliminate unauthenticated URL downloads. * Eliminate unmarshalling of unauthenticated code. * Eliminate execution of unauthenticated code. * Eliminate StackOverflowError's in the client thread, caused bysending spurious garbage over InputStream's. * Eliminate StackOverflowError's in the client thread, caused by substituted jar files or URL's from DNS cache poisoning attacksetc. How? * Delay granting DownloadPermission, until remote endpoint hasauthenticated itself, we trust the remote endpoint to advise asuitable URL, if it authenticates.* Authentication by annotating a reflective proxy (additional to the Codebase String) from the remote endpoint, used for authenticationand to provide CodeSource Certificate[]'s. This may be different to the Service, if a remote object is marshalled elsewhere (eg another client).* Delay granting ClassLoadingPermission, until remote endpoint has authenticated itself and has provided the expected CodeSourceCertificate[]'s* Perform unmarshalling in a controlled ExecutorService thread.So all we're doing different is authenticating the remote end and if it authenticates permit downloading and classloading. There is one more scenario to consider, currently this is a mechanism to protect against download and deserialization of unknown code for smart proxy's. But what about Service that only use reflective proxy's and don't require downloaded code? But what if we don't want to grant download permission or class loading permission to a Subject we authenticate? Currently the unmarshalling code doesn't run as the Subject after authentication, this means the Permission grant's are only dependent on authentication, something Michal pointed out earlier when this was proposed. Now this code can be easily changed so the granting permission operation is run as the Subject after authentication, this would allow us to distinguish between different Subjects. The drawback is that performance won't be as good, but it seems the most logical and powerful approach. What do you think? There is one last obstacle, if Certificates are used to sign the jar files, how do you effectively prevent one Subject from using another Subject's signed CodeSource's if Code signing is used for isolation of separate Subjects namespaces? A service could deliberately attempt to occupy the same namespace as another Service to attempt to gain information via shared static variables. We need to prevent this occurring. This has to be done with the ClassLoader, but during unmarshalling, the service proxy has not yet been verified. The authentication proxy delivered with the MarshalInputStream may not have the same Subject as the Service, it could be a third party. Could it be that when the smart proxy is unmarshalled, and executed as it's Subject, it must contain a Certificate matching the signer of the Codebase? We're on the cusp of solving this problem, thoughts? Cheers, Peter. Peter Firmstone (JIRA) wrote:Denial of Service during unmarshalling of smart proxy's ------------------------------------------------------- Key: RIVER-362 URL: https://issues.apache.org/jira/browse/RIVER-362Project: River Issue Type: Bug Environment: Untrusted networks Reporter: Peter FirmstoneDuring unmarshalling of smart proxy's there's a period before the proxy has been verified (authenticated) where deserialization methods are executed on untrusted code, the potential exists for untrusted code to perform denial of service.
