An interesting point:
Q: Unicast discovery can use JERI-SSL Endpoint's but is not subject to
the unmarshalling attack, why not?
A: It doesn't use unmarshalling, instead, the connection is
authenticated before the proxy is downloaded. Discovery code already
knows the interface to expect: ServiceRegistrar. It applies any
remaining method constraints to the proxy after the proxy is created.
So it dawned on me that the problem with Reggie (our existing lookup
service implementing the ServiceRegistrar interface), is it uses
MarshalledInstance.
When the lookup service stores and later retrieves a service proxy, it
already knows the proxy service interface and classes. But to allow the
proxy to utilise any communication method it wishes, the connection
implementation choice is left to the proxy. Now this makes sense on
trusted networks, but that flexibility comes at the expense of security.
What's the alternative?
Provide a ServiceItem (subclass) that contains Entry's, ServiceID and a
URI (when we decide the appropriate format), which can be used to
establish an Endpoint connection.
The ServiceRegistrar2 proxy doesn't need to perform unmarshalling on the
client, instead a connection is made directly to the service by the
ServiceRegistrar2 proxy, on behalf of the client. If MethodConstraints
are not satisfied, the proxy is never downloaded.
Now since we're applying method constraints, which may include minimum
principals, authentication, integrity and confidentiality, the only
remaining task for the client to perform is proxy verification. This
could also be complimentary to maven provisioning. Maven provisioning
doesn't solve deserialization privilege escallation attacks, no
deserialization whatsoever should be performed before authentication.
This functionality would be limited to ServiceRegistrar2, the existing
ServiceRegistrar would behave as it always has.
A client could then avoid the unmarshalling attack, but would have to
ensure that it trusts the ServiceRegistrar2 first.
public interface ServiceRegistrar2 extends ServiceRegistrar{
/**
* Returns a ResultStream that provides access to
ServiceClasspathSubItem
* instances. The ResultStream terminates with a null value. The
result
* stream may be infinite, or limited by an integer limit value.
*
* A ServiceClasspathSubItem implementation instance is a
ServiceItem that
* contains only Objects that are resolvable on the local classpath,
* this is useful for clients to perform filtering before requiring a
* download of the actual ServiceItem.
*
* The ResultStream should be closed once the desired service has been
* found, or services have been processed.
*
* @param tmpl template to match
* specified template
*
* @param maxBatchSize held locally, larger batch sizes reduce network
* traffic, but may delay processing locally depending on
implementation.
* @param limit - Zero for infinite, otherwise limits the number of
matching
* results.
* @return ResultStream containing ServiceItem's
* @throws java.io.IOException
* @see ServiceItem
* @see ServiceClasspathSubItem
* @see ResultStream
* @see ServiceResultStreamFilter
* @see ResultStreamUnmarshaller
* @since 2.2.0
*/
ResultStream lookup(ServiceTemplate tmpl, Class[] entryClasses,
MethodConstraints constraints,
int maxBatchSize, int limit) throws IOException;
}
/**
* <p>
* ServiceItemClasspathSub is intended for client side filtering of lookup
* service results prior to clients using a service, the lookup service
* that implements this class, implements #getServiceItem(), so clients
* can obtain a complete ServiceItem when required after filtering.
* </p><p>
* ServiceItemClasspathSub extends ServiceItem and can be used anywhere a
* ServiceItem is required for querying or inspecting Entry fields that are
* resolvable from the local classpath. If dynamically downloaded code is
* required, Remote or Serializable object references are not resolved,
* instead, such fields are set to null to avoid codebase download.
* </p><p>
* ServiceItemClasspathSub inherits all fields from ServiceItem.
* </p><p>
* Some fields in ServiceItemClasspathSub may be null or fields in
Entry's may
* be null or even the service reference may be null, these fields
would be
* non-null in a ServiceItem that resolves classes from dynamically
downloaded
* code or a remote codebase.
* </p><p>
* The serviceID field shall be non-null always.
* </p><p>
* ServiceItem's toString() method will return a different result for
* ServiceItemClasspathSub instances.
* </p><p>
* When required, a new ServiceItem that is unmarshalled
* using remote codebases and dynamically downloaded code can be obtained
* by calling #getServiceItem().
* </p>
*
* @since 2.2.1
*/
public abstract class ServiceItemClasspathSub extends ServiceItem{
private static final long SerialVersionUID = 1L;
protected ServiceItemClasspathSub(ServiceID id, Entry[]
unmarshalledEntries){
super(id, (Object) null, unmarshalledEntries);
}
/* Default constructor for serializable sub class.
*/
protected ServiceItemClasspathSub(){
super(null, null, null);
}
/**
* Using remote and local code as required getServiceItem returns a
* new ServiceItem.
*
* The returned ServiceItem must not be an instance of this class.
*
* @return ServiceItem, totally unmarshalled, using remote codebase
resources
* in addition to any local classpath or resources.
*/
public abstract ServiceItem getServiceItem();
}