river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Re: Distributed network security
Date Sun, 01 Jul 2012 04:45:58 GMT
Thanks Dan & Gregg,

I've been working on the overhead problem, here's a summary (will commit 
the latest after tests finish):

   1. Removed calls to CodeSource.implies (this causes a DNS lookup)
   2. Replaced URL with URI in Policy providers (URL requires DNS lookup
      and File system access)
   3. Removed calls to SocketPermission.hashCode and equals (this causes
      a reverse DNS lookup)
   4. Replaced URL with URI in maps inside PreferredClassLoader and
   5. Changed the behaviour of Reference Collections to avoid calling
      hashCode during initialisation of temporary and timed referrers.
      (to avoid calling SocketPermission.hashCode).
   6. Created a PermissionComparator to avoid broken equals and hashCode
      implementations in Permission classes.
   7. Optimise the order of Permission checks (further optimisation is
   8. Added dnsjava nameservice provider - a local dns server written
      entirely in java that supports multi threading and reverse DNS
      lookup, so many SocketPermission.implies instances can execute in
      parallel and avoid long timeouts (dnsjava has had 13 years of
      development and is relatively stable).  This requires a system
      property to be set.
   9. CachingSecurityManager uses Cliff Click's high scaling hash map
      implementation, proven to scale linearly to over 500 threads and
      Doug Lee's ConcurrentSkipListSet which is also concurrent.  This
      caches permission checks for each AccessControlContext and uses
      the PermissionComparator to avoid calling equals or hashCode. 
      Timed references reap permissions from the cache after about 10
      minutes of non use using a background thread.  Soft Permissions
      were not suitable.
  10. Immutable PermissionGrant's; the Policy uses these to make policy
      decisions, these are shared among many threads without blocking. 
      PermissionCollection instances are created on demand then
      discarded, since PermissionCollection is typically single threaded
      and synchronized.  Permission objects are meant to be immutable so
      they should be non blocking, some like SocketPermission aren't
      (they wait for dns lookup results if other threads are executing
      the same lookup) but with dnsjava they are much better.

So I hope I'm fixing security enough to stop people switching it off 
altogether. River is more exposed to Java 2 security kinks than other 
software because it is so network orientated, but I haven't really gone 
outside the original Java 2 security model, I've created completely new 
file policy, dynamic policy and security manager implementations, java 2 
security was designed with this flexibility in mind.

I think we've got the only scalable java security infrastructure, I'm 
hoping future deployment will bring more patches and further improvements.

Code needs to access more resources than users like ProtectionDomains, 
ClassLoaders and system properties, however users are more concerned 
with access to files and network.  In Unix, everything is a file reduces 
access control complexity.  Plan9 was designed as a distributed network 
os also based on the everything is a file concept.  The protection 
domain concept that Java uses was inspired by Multix.

The intersection of permissions contained by protection domains on the 
stack at any point in time determine the available permissions.

I've found that each time we've changed our java platform dependencies 
and compiler options, I've had to modify the test policy files, simply 
because code follows different execution paths and different domains are 
on the stack at the time the permission check is called.

Now here is where it gets interesting, as Dan pointed out, most 
administrators are happy to just allow a user all network access and 
restrict it using a firewall.  But if it enables smart proxy's from 
behind the firewall to serve clients beyond the firewall (lets imagine 
for a moment that UDT Sockets have solved that problem), that could be 
seen as circumvention by an administrator.  However if user Principals 
are not injected into every domain on the stack, and there is less 
trusted code on the stack, the user will only have the permissions of 
the less trusted code while it remains on the stack.

So in the presence of trusted code, user polices are relatively simple, 
but in the presence of less trusted code, the code doesn't gain the full 
permissions of the user and user privileges can be much more relaxed and 
remain simple.  Principals and code become separate concerns.

This is why I think that the design of SubjectDomainCombiner is not 
suited to River, without some subtle modifications to add a Subject 
ProtectionDomain to the stack rather than injecting the Subject's 
principals into every ProtectionDomain on the stack.

Then as Dan has suggested, services can expose the permissions they 
require, this then drops the users privileges to that of the less 
trusted code, while that code remains on the call stack (it will be 
removed after method calls have returned).

In fact codesources can expose the permissions they require through 
permissions.perms files similar to OSGi, then we have to decide whether 
we trust the code enough to grant permission and that usually requires 
someone to vouch for it, like the server Subject or a code signer.  So 
we need a different way to contact the server in an entry or something 
prior to class loading and unmarshalling.

If we create an Entry specifically for Identity Certificates, an entry 
containing the permissions and a service with a reflective proxy used 
for obtaining authority certificates, then provided that delayed 
unmarshalling of the smart proxy is used, we are in a situation where we 
can grant DownloadPermission to the smart proxy, perform proxy 
verification then grant all remaining permissions to it.  We could even 
have MarshalledInstance heavily restrict the Permission available during 
unmarshalling, even when the stack contains only privileged code so 
ClassLoaders cannot be created by untrusted code (requiring no 
administration).  There is a small period during class loading when the 
class's ProtectionDomain isn't on the call stack, when static 
initialisers and so forth can get up to mischief and wreak havoc. We 
must ensure that something unprivileged is on the stack during 
unmarshalling.  When the MarshalledInstance has returned it is removed 
from the stack, but the new untrusted smart proxy PD is now on the 
stack, so there is nothing to worry about.  A ProtectionDomain isn't 
assigned to a Class until the Class object has been instantiated.

Then I think we should be able to abstract it all using something along 
the lines of what Gregg is describing, especially if we've simplified 
the user model, so we don't have to be as concerned about untrusted code.

I'm not saying it's easy, nor do I have a specific abstraction model in 
mind, I'm very flexible and open to suggestion.

I think the untrusted code complexity issues are solvable (rather than 
require only trusted code, because this spoils the dynamic flexibility 
of Jini) we could provide a tool to perform runtime permission auditing 
developers can expose the permissions required by their services, if you 
have a look at  CombinerSecurityManager there is a method:

protected boolean checkPermission(ProtectionDomain pd, Permission p){
        return pd.implies(p);

Just override this and create a Map that collects all the permissions 
required by each ProtectionDomain and dump it to a file.

An administrator could determine in advance the permissions that users 
can grant to downloaded code with GrantPermission, effectively 
sandboxing code in, because you can't always trust users not to grant 
permission they don't understand to dancing pigs.

Administrators obviously get to grant more.

Thanks for the comments, much appreciated.



Gregg Wonderly wrote:
> On Jun 30, 2012, at 2:39 AM, Dan Creswell wrote:
>> I'd also suggest that too much permission is granted because the current
>> Java security infrastructure inevitably works on a highly granular level
>> with long lists of detailed security options for this or that. That brings
>> a lot of overhead and complexity. Unix filesystems essentially reduce the
>> problem to user, group, other that classification whilst sometimes unwieldy
>> also makes for a level of sanity in terms of the number of permissions that
>> need playing with or expressing.
>> It seems to me that we should be looking at similar tactics for
>> grouping/abstracting that take out the need to hit a long list of very
>> granular permissions.
> This is the whole, complete and total issue from my perspective.  For me, Java permissions
represent the totality of exposure you want to give the system, to your software.  It has
nothing to do with what "roles" or "users" need, it's just a ton of detail, which practically
might be different from day to day, deployment to deployment and otherwise creates tedium
which, turns people off.
> For me, the services "features" are what I want the user to be controlled with.  At the
method level, I want to be able to say "which role" gets to use "which arguments".  This can
turn into a lot of tedium too though.
> However, I really feel it makes more sense to say things like the following which enumerate
"functions" which certain roles can perform.
> admins -> browse,add,edit,delete,admin
> techs ->browse, edit
> viewers->browse
> managers->browse,add,edit,delete
> If you create this kind of role mapping, and then take each of the services methods,
and lump them into one of the functions, you've mapped out a decently concise view of what
you need to happen.
> My http://java.net/projects/authlib project provides a complete mechanism which allows
you to formulate XML descriptions of this type, and from that XML, generate delegating service
classes, which then use a JDBC database, to load/maintain an in memory view of the security
> There is an admin ServiceUI which lets you create all the roles and permissions etc.
> I suspect that this seems quite complicated, compared to managing permissions, but, it
actually allows you to configure security using what I feel is the right domain of details,
which then makes it a lot easier to actually use security.
> Gregg Wonderly

View raw message