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.

Reply via email to