What follows is relatively hard core security, but it's relevant to anyone wishing to deploy on untrusted networks. I know some people don't like discussing security issues for fear of turning off would be developers but security isn't mandatory, however considering that River/Jini is already making extremely difficult tasks possible, I think it appropriate to continue focusing on solving difficult issues, especially considering recent online coverage and increasing awareness of java security issues. In the long run this will make life easier for developers.
Java 2 security infrastructure was originally designed around codebase trust, but it's also extensible and customisable, JAAS was designed around the premise of user security concerns, previously lacking from Java 2, code was assumed to be trusted in most cases, although it's also still possible to restrict permission to a combination of principals and codesources or certificates, but in practise, permission is generally granted to principals. JAAS uses the SubjectDomainCombiner to inject principals into every protection domain on the call stack (well it replaces them actually, but that's an implementation detail). To ensure that only trusted code is used by authorised principals, policy file permission grants must be made that includes both the signer of the code and the principal authorised. Failure to include the code signer in the permission grant may allow untrusted code to gain elevated permissions on the call stack by being executed by an authorised principal. In a distributed environment it is difficult if not impossible to know in advance which code signers and principal grant combinations are required, these interactions and introductions may occur dynamically at runtime. For this reason, too much permission is often granted, in order to allow the software to function intuitively or as anticipated by users, leaving security holes for opportunistic attackers. A user is bound to a single thread and all child threads inherit its context. Executors and Thread pools may execute tasks on behalf of users however user AccessControlContext must be copied from submitting threads. SubjectDomainCombiner is extendable, it isn't final, JAAS behaviour can be subtly modified without having to reinvent the wheel. So what changes need to be made to SubjectDomainCombiner functionality to allow the mixing of Principal grants with codebase or codesigner grants in the presence of untrusted code without compromising security? Instead of injecting Subject principals into every ProtectionDomain on the stack, add a new ProtectionDomain, containing the Subject's Principals to the existing stack. In the presence of untrusted code, priviledge is reduced to the intersection of commonly held Permissions, instead of being elevated to those of the principal. ProtectionDomain would also need to be subclassed, eg SubjectProtectionDomain, so the SubjectDomainCombiner could identify and replace the SubjectProtectionDomain when running as another more privileged Subject in a privileged context (equivalent to that effected by Subject.doAs). This also requires that other ProtectionDomain's without Principals will require all necessary permissions granted in policy statements. Unfortunately it is much simpler to make all the necessary grants only to Principals and associate them with Subjects upon login. It takes considerably more effort to determine all the code sources that require these permissions, a deployment simulation tool could greatly simplify determining permission requirements during deployment, so it doesn't become an impediment to adoption, but has rather the opposite affect. According to current policy behaviour, a ProtectionDomain with a null CodeSource would not be granted any Permission, ever! A ProtectionDomain containing a CodeSource with null URL can however be granted Permission, provided no codesource is specified in relevant policy file grant statements. A Principal only ProtectionDomain would need to have a CodeSource with null URL, to avoid any unexpected behaviour when combined in the stack. JAAS was designed so permissions are not granted until after a user has authenticated so trusted code cannot perform privileged tasks such as connecting to a network until after a user is logged in, however a system where trusted code is granted permission it already has sufficient permission. Authentication in this case would inject a ProtectionDomain on the stack that reduces privileges. Log-in represents a lessening of permission. This will work if the only way for the user to access the functionality the code provides is by logging in. The question is, which is easier to control, untrusted code that may be able to gain privilege by running on a user thread (a trojan) or trusted code logging in users? The former is indeterminate in an environment where untrusted or semi trusted third party code exists. The beauty of SPKI/SDSI is it can be used as glue between separate domains of authority, allowing each to use disparate systems and be responsible for delegating authority granted by external entities within their own domain. In SPKI/SDSI, a subject is represented by a public key, a user can have associated authorisation certificates, these certificates can be delegated to authorise a user to perform tasks in another administration domain belonging to another company. Using the DynamicPolicyProvider and PermissionGrant interface, an authority certificate having an expiry date, could be verified and dynamically granted. SPKI/SDSI allows the security framework to determine authorisation, without concerning itself with authentication, simply by the association of authority certificates with a public key (Subject), authority certificates only have value to the Subject that originally granted them (typically an admin), so the authority that granted these certificates will be the administrator of the domain where the certificates are presented as evidence of authorisation by some remote client. Since there may be a combination of different codebase signers in use at the same time, it isn't practical to combine this grant with a signer, the code has to be assumed trusted, however the reality is that not all code is trusted. Instead a jar file could contain an address where authorisation certificates can be retrieved. The new security manager lends itself to the creation of a runtime security tool that can create policy files based on least privilege principles under controlled conditions simulating the deployment environment. The policy file produced will need some editing for portability, since all environment variables are expanded, it will be useful to enable developers to determine security policy requirements for each ProtectionDomain and User role. Adopting least privilege principles for tasks eliminates unidentified and existing security bugs, such as deserialisation attacks, similar to CVE-2010-0094 RMIConnectionImpl and CVE-2008-5353 ZoneInfo object deserialization demonstrated by deserializing Calendar objects. This happens because ClassLoader.defineClass needs to load the class file before it can define the ProtectionDomain so the deserialising class's ProtectionDomain is not on the stack, readObject() is called with reflection, it isn't part of an inheritance hierarchy. Sun's bug fix limited the permissions to those that were required by the Calendar class. DownloadPermission cannot prevent this BTW because readObject() is executed in a privileged context, a custom ClassLoader can be created bypassing PreferredClassLoader. Least privilege limits permissions to those required to perform intended tasks, even so called trusted jvm library code can have limited privileges. If you need to deseralize Calendar objects, don't grant any unnecessary privileges, this fixes bugs without changing code. Least privileged principles limit privileged code blocks ability to do anything other than what's absolutely necessary. Even though the java 2 security architecture was designed to support least privilege, it is seldom implemented that way in practise, increasing the opportunity for crackers to find exploits. Although none of this will make it into the upcoming release, it may make the following and I'd like to finish security prior to implementing UDT sockets to enable internet based services and DNS SRV based discovery and codebases. Peter.
