You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@river.apache.org by Peter Firmstone <ji...@zeus.net.au> on 2012/07/01 06:45:58 UTC
Re: Distributed network security
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
PreferredClassProvider
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
possible).
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.
Cheers,
Peter.
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 model.
>
> 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
>