Thanks Gregg,

The services you deploy are often unique, but relevant and it's apparent you've been able to explore and delve deeply into complex problems. I'm grateful that both you and Dan are finding some time to discuss this issue, because to be quite honest, I'm not happy that I fully grasp the issues myself and discussion helps to improve understanding.

You've also hit the nail on the head, it's about limiting permission while executing as a Subject while further limiting permissions available to the proxy, but still allowing the Subject to have more permission when the proxy isn't on the call stack. It was also about separating Principal and CodeSource concerns, so you don't need to ensure that all your policy grant files include CodeSource and Principals. - But it turns out that this isn't necessary there is an alternative option that follows:

Dynamic grants made to proxy's usually include the CodeSource and Principals, in the current case, the permission granted can be less than with the same Principals executed only in the presence of signed trusted code, the dynamic grant is very specific, to be granted permission the code must have the proxy ClassLoader and be executed by a Subject with the Principals specified in the grant.

If the proxy doesn't have AuthPermission("doAs"), get the current context by calling AccessController.getContext() this will contain the proxy's ProtectionDomain if it has already been unmarshalled, then use AccessController.doPrivileged to execute Subject.doAsPrivileged(Subject, PrivilegedAction, AccessControlContext), which injects the Subject principals into the proxy codebase, without allowing the proxy to gain the privileges the Principals have in the presence of trusted signed code.

Rather than modify SubjectDomainCombiner, the alternative option described above works by signing all your local code (some additional work for the developer) and all Principal based grants must also include signed by, so those principal grant's can't be stolen by untrusted code, because untrusted code it isn't signed with the Certificates stated in the policy file. No grant should be made to a Principal alone, it must include a CodeSource URL or a jar Signer. BTW, ConcurrentFilePolicy uses CodeSource URI's not URL, a small change of semantics for a big performance gain.

Another benefit of signed code is it protects local package private security boundaries, of course this will create more errors if you haven't got your preferred lists right.

So we could provide two additional methods in net.jini.security.Security, but without modifying SubjectDomainCombiner, while also preserving current policy behaviour, to ensure that the AccessControlContext used in Subject.doAsPrivileged is not null.

I guess what I've also just shown is that granting to a combination of CodeSource / Signers and Principals is determinate as Dan mentioned in a previous post, so yes, Dan was right.

Do you think a practical way for an administrator to limit the Permissions a Subject can grant to a service proxy is by limiting them with GrantPermission? It allows the Subject to have more permission (in the presence of trusted signed code) than it's capable of granting.

The proxy could make available a list of Permissions it needs within the jar file as you've suggested.

My gut feel is permissions should be granted by the Subject to the proxy (in the presence of trusted code), however since not all Subjects are people, this mechanism needs to be flexible. Any ideas? Events?

We can also determine if a Subject can grant a subset of the Permissions requested by the proxy, by creating a ProtectionDomain that contains the Principals and required Signer Certificate (this won't work for CodeSource URL's only signed code), then ask the Policy for it's PermissionCollection, then check GrantPermission for each permission on the list.

This is where things get a little interesting, since Subject.doAsPrivileged or Subject.doAs can be used to perform the dynamic grants, there are traps for the uneducated.

Privileged context must not be used as the context to communicate with the proxy itself, so it's beneficial to developers if we provide the methods to perform high risk tasks without requiring the proxy to have AuthPermission("doAs"). Prior to receiving dynamic grants, the proxy, even if injected with Principals does not have Principal privileges, hence privilege escalation is impossible, provided all grants to principals also require a trusted jar signer. We can even pass the proxy class to these methods, so they can ensure the proxy's ProtectionDomain is on the stack, prior to making any method calls to avoid deserialisation attacks.

Some supporting information:

  1. Deserialisation Attacks: During deserialisation, there is a small
     time period during class loading where privileges must be
     minimised. Deserialisation privilege escalation attacks rely on
     deserialisation being performed in a privileged context while the
     ProtectionDomain of the object being deserialised is not yet on
the stack. Google deserialisation attacks if you're interested. We should also add a PD with restricted privileges to the stack
     while MarshalledInstance performs unmarshalling, just to make sure
     that all deserialised object have no more privileges than required.
  2. Thankfully this bug has been recently fixed:
     
http://slightlyrandombrokenthoughts.blogspot.com.au/2010/04/java-trusted-method-chaining-cve-2010.html
  3. In Jini security documentation I've seen on the web,
     Subject.doAsPrivileged is called with a null AccessControlContext
     executing the proxy, in doing so the proxy PD is no longer on the
     stack, however it isn't clear when the proxy ProtectionDomain will
     be added back onto the stack, will it be possible for an object to
     be deserialised in a privileged context?  It's highly possible,
     because of delayed class loading.
  4. N.B. I'm not talking about denial of service during unmarshalling,
     where the attacker is simply of nuisance value, say running an
     unending loop or using up all memory.  In this case the user can
     just kill the jvm and start again.  No deserialisation attacks can
     allow creating ClassLoaders or setting the SecurityManager in
     privileged context.

Solution:

Always ensure a domain with minimal privileges exists on the stack during deserialisation.

Cheers,

Peter.

Gregg Wonderly wrote:
On Jul 7, 2012, at 8:02 AM, Peter Firmstone wrote:

These doAs methods in this case cannot elevate Permission, they can reduce 
Permission to that which the Subject has in common with other code on the 
stack, but it cannot be used by code to gain privilege if it uses a custom 
DomainCombiner that extends SubjectDomainCombiner.

Would this be an acceptable compromise?

In future, we can look at other tools to assist with simplifying security, such 
as static bytecode analysis or FindBugs perhaps.

When I am using remote code, I either trust it by source, or don't, and can assert that trust by 
granting AllPermission for the URL, or not.  Adding local resource access to a proxies code base, 
is usually limited to network access, but sometimes file access for certain UIs which, for example, 
have images which my caching URLHandler will store on disk.  That access to local resources, 
whether through Subject grant, or blanket permission is what matters for using a services 
ServiceUI.  When I use a services proxy for interaction, I've always used JAAS login services to 
gain access, via PAM login services on Linux and other PAM supporting OSes using JNI mechanisms.  
Thus, there is a Subject created which has a set of Principals that my LoginModule creates in the 
form of a "user" and any "groups" that the user is a member of.

In the services, I always use Subject.doAs with those subjects, and could use 
user or group based permission grants in my policy.  But, in the end, I never 
found that to be needed, and I instead, grant permissions to the codebase at 
the appropriate granularity (never granting to or using a client side codebase 
jar).

The authorization framework that I've mention here, before, is then used to do 
role based control of how the API is used on the server, by the calls into that 
environment from the client.  I have a InvocationHandler that I insert to do 
the Subject.doAs() on the server side.  So, when the user authenticates with 
the server, I get a Subject.  I do Subject.doAs() to create an instance of the 
InvocationHandler (which holds a reference to the Subject), and the exported 
smart proxy instance, which is returned to the client.

When a Subject asserts some kind of client local controls, it could provide 
some new functionality as you illustrated. In the case of network access 
control, or other local resource access, it could allow you to limit access to 
those resources, or to extend access in particular ways with a dynamic policy 
grant, on the client.

I crafted some code in that direction at one point.  It allowed the jar to have 
a list of permissions in it, that it wished to have granted, and I was trying 
to decide what the right interface would be, to allowing the client software to 
talk to the user about these permissions.  In a sense, this was along the lines 
of Java WebStart kinds of thoughts.  My ServiceUI desktop has a code flow at 
the point that the UI is activated, that it could obviously do a resource query 
into the jar, find the requested accesses, and prompt the user to grant them.

Conversely, you want to limit permissions by asserting a domain controlled by 
the Subject, that would provide whatever access you granted to the Subject in 
that domain/policty.  So, at the time that a client UI is first activated, you 
could use information about it being an uncontrolled codebase to trigger the 
assertion of the Subject controlled domain.

What I think we need to focus on, are these two mechanisms (grant to client 
thread/Subject jar requested permissions and limit of client thread to already 
asserted Subject based domain) and the obvious fact that it's really about 
asserting control into the client execution environment.  We need to work on 
how we'd decide that needed to happen, and then think about whether it's just 
Subjects we want to assert, and whether we need to include the Privileged forms 
or not.

Gregg Wonderly

Reply via email to