I'm going to raise this as an issue on Jira, however I want to be sure I haven't overlooked something first, so I've cc'd this to a number of you, I know many of you are busy, so won't be offended if you're unable to weigh in, if there are other reasons for not responding to the list please feel free to correct any of my assumptions directly.

In a djinn (Jini network environment) You can limit untrusted code from gaining permission by ensuring policy permission grants, include both the Principal && ( CodeSource URL || Signer) and by only granting trusted code AuthPermission("doAs").

But what if I want to run as a Subject with untrusted code?

To run as a Subject, you have to trust the code and it must have AuthPermission("doAs"), unfortunately, this allows the code to run as ANY subject, which may be undesirable, if "doAs" is granted, there are no restrictions as to which Subject the code may run as, including an administrator if it finds itself on the stack at the right time, this might allow code to perform a privilege escalation attack.

To allow a user to execute some task via a smart proxy service, AuthPermission("doAs") must be granted to the smart proxy after verifying proxy trust.

But what if we want to use a service with a smart proxy without granting trust? So I can use it while running as my Subject, allowing me to use my public credentials for authorisation to run as my Subject on the services server (with another set of Principals assigned by the service server), without granting smart proxy code my local Principal Permissions from my local domain. I want to allow Subjects to cross authority domains (personal, company and country network boundaries), where trust relations aren't implicit.

Under certain circumstances in a dynamic distributed environment like River; we don't always know in advance who the code Signers will be or which CodeSource URL will be utilised (which is why we have DynamicPolicy; the server Subject vouches for the proxy code).

For example, if you provide a collaboration service (via the internet), which utilises handback objects from clients (a handback object could be another service proxy), when client Subjects log in to use the service, there is a risk that another clients code is on the stack at the time Subject.doAs is called, enabling it to access information that is only intended for the user that has just logged in, by Subject.doAs injecting it with the another users principals and running on the another users thread, in doing so the ProtectionDomain on the new user thread call stack no longer contains the original Subject's Principals, but now only the new user / Subject's Principals.

This issue is specific to Jini / River because of the power of dynamic code.

Although this power isn't fully utilised now, it may be in the future, if Jini services are made available on the internet.

One solution might be to add methods similar to Subject's static methods to net.jini.security.Security.

As I mentioned earlier (see Re: Distributed Network Security), we could extend and modify SubjectDomainCombiner to add a SubjectProtectionDomain to the call stack, instead of adding Principals (privileges) to all ProtectionDomains on the stack at that point in time. This way we no longer need to check for AuthPermission("doAs") and untrusted code is prevented from performing a privilege escalation attack if it exists on the call stack at the time another user Security.doAs(Subject, PrivilegedAction) is called.

There are other subtle kinks with SubjectDomainCombiner (implementation):

When an administrator adds or removes a Principal from a Subject, the ProtectionDomains on the stack are not updated, this requires a user to complete the PrivilegedAction before changes are effected.

If we have SubjectProtectionDomain and add it to the call stack, we don't need to add Principals to every ProtectionDomain, instead the SubjectProtectionDomain asks the Subject for the Principals. This allows dynamic updates to be effected immediately, without requiring the user to log out and in again. Implementing equals and hashCode in SubjectProtectionDomain would no longer require caching of ProtectionDomain instances too.

Each domain is responsible for assigning Principals to Subjects, Subjects may have different Principals in different domains.

It's worth noting that Oracle has been fixing deserialisation privilege escalation attacks, when downloaded code doesn't yet appear on the call stack and privilege escalation attacks by classes that extend trusted classes, but don't override their methods allowing them to avoid appearing on the call stack.

We can use similar methods to limit privileges during proxy class initialisation during unmarshalling in MarshalledInstance.

I propose adding the following static methods to net.jini.security.Security:

  public static <T> T doAs(final Subject subject,
           final PrivilegedAction<T> action) {
       throw new UnsupportedOperationException("not implemented");
   }
public static <T> T doAs(final Subject subject,
           final PrivilegedExceptionAction<T> action)
           throws PrivilegedActionException {
       throw new UnsupportedOperationException("not implemented");
   }
public static <T> T doAsPrivileged(final Subject subject,
           final PrivilegedAction<T> action,
           final SecurityContext context) {
       throw new UnsupportedOperationException("not implemented");
   }
public static <T> T doAsPrivileged(final Subject subject,
           final PrivilegedExceptionAction<T> action,
           final SecurityContext acc)
           throws PrivilegedActionException {
       throw new UnsupportedOperationException("not implemented");
   }

Where SecurityContext is determined by calling Security.getContext(). SecurityContext contains the AccessControlContext in addition to any other context settings, like the context ClassLoader.

We would require a Security Property to be set to allow these methods to behave identical to existing JAAS Subject static methods OR to behave as proposed.

// Security Property
String subjectBehaviourProperty = "net.jini.security.Security.distributed_domain_subjects";

DynamicPolicy grants would also need to subtly change the way Security.grant methods operate when the property is true, both the proxy ClassLoader and the Principal must be granted necessary permissions separately as they will appear in separate ProtectionDomains in the active AccessControlContext.

DistributedSubjectDomainCombiner would extend SubjectDomainCombiner and effect the required changes, only one SubjectProtectionDomain would exist on the stack at any time.

Compatibility would be maintained with existing JAAS providers etc.

Policy files may need to be written a little differently to reflect the separation of concerns of Principal and CodeSource permissions.

Penny for your thoughts?

Best Regards,

Peter Firmstone.

Reply via email to