Return-Path: Delivered-To: apmail-incubator-river-dev-archive@minotaur.apache.org Received: (qmail 42311 invoked from network); 5 Feb 2011 11:04:01 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 5 Feb 2011 11:04:01 -0000 Received: (qmail 98121 invoked by uid 500); 5 Feb 2011 11:04:01 -0000 Delivered-To: apmail-incubator-river-dev-archive@incubator.apache.org Received: (qmail 97997 invoked by uid 500); 5 Feb 2011 11:03:59 -0000 Mailing-List: contact river-dev-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: river-dev@incubator.apache.org Delivered-To: mailing list river-dev@incubator.apache.org Received: (qmail 97989 invoked by uid 99); 5 Feb 2011 11:03:58 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 05 Feb 2011 11:03:58 +0000 X-ASF-Spam-Status: No, hits=0.7 required=5.0 tests=RCVD_IN_DNSWL_NONE,SPF_NEUTRAL X-Spam-Check-By: apache.org Received-SPF: neutral (nike.apache.org: local policy) Received: from [61.9.189.137] (HELO nschwmtas01p.mx.bigpond.com) (61.9.189.137) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 05 Feb 2011 11:03:48 +0000 Received: from nschwotgx04p.mx.bigpond.com ([61.9.223.241]) by nschwmtas01p.mx.bigpond.com with ESMTP id <20110205110325.WJIB7337.nschwmtas01p.mx.bigpond.com@nschwotgx04p.mx.bigpond.com> for ; Sat, 5 Feb 2011 11:03:25 +0000 Received: from [10.1.1.2] (really [61.9.223.241]) by nschwotgx04p.mx.bigpond.com with ESMTP id <20110205110324.JMLF781.nschwotgx04p.mx.bigpond.com@[10.1.1.2]> for ; Sat, 5 Feb 2011 11:03:24 +0000 Message-ID: <4D4D2D00.4050203@zeus.net.au> Date: Sat, 05 Feb 2011 20:57:04 +1000 From: Peter Firmstone User-Agent: Thunderbird 2.0.0.14 (X11/20080531) MIME-Version: 1.0 To: river-dev@incubator.apache.org Subject: The internet - Proxy Isolation - Denial of Service Attack. Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-RPD-ScanID: Class unknown; VirusThreatLevel unknown, RefID str=0001.0A150201.4D4D2E7D.0008,ss=1,fgs=0 X-Virus-Checked: Checked by ClamAV on apache.org The following class, isolates a proxy on it's own thread and using reflection, isolates it completely from the rest of the executing environment, by passing method calls as tasks. Forgive the tab formatting. Cheers, Peter. /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.river.impl.security.dos; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Collection; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import net.jini.io.MarshalledInstance; /** * A preliminary experiment into Isolating a Smart Proxy. * * I think I'll investigate creating a Permission for additional threads * for improved performance and also creating an event model so clients * don't need to wait for remote method returns. I'll create a new interface * for this, that can be implemented by services directly too. * * Alternative, only maintain this data structure for as long as it takes * to verify proxy trust, then return proxy to the client or have the client * thread call the smart proxy via the reflection proxy directly. * * REMIND: Investigate subclass method returns, this would be simple, if the * smart proxy is confined to it's own ClassLoader, we just check the class * of the object returned isn't from that ClassLoader, unless the smart proxy * has a ServiceAPISubclassPermission or something like that. * * @author Peter Firmstone */ public class ProxyIsolate implements InvocationHandler { private volatile Object smartProxy; private volatile ExecutorService proxyExecutor; private volatile Throwable thrown; private final long timeout; private final TimeUnit unit; @SuppressWarnings("unchecked") public ProxyIsolate(MarshalledInstance proxy, ClassLoader defaultLoader, boolean verifyCodebaseIntegrity, ClassLoader verifierLoader, Collection context, long timeout, TimeUnit timeUnit ) throws TimeoutException, InterruptedException, ExecutionException{ this.timeout = timeout; unit = timeUnit; thrown = null; proxyExecutor = Executors.newSingleThreadExecutor(new Factory(this)); UnmarshallProxyTask task = new UnmarshallProxyTask(proxy, defaultLoader, verifyCodebaseIntegrity, verifierLoader, context); smartProxy = proxyExecutor.submit(task).get(timeout, timeUnit); } private Object taskInvoke(Object proxy, Method method, Object[] args) throws Exception { String methodName = method.getName(); if (method.getDeclaringClass() == Object.class) { // Handle the Object public methods. if (methodName.equals("hashCode")) { return new Integer(System.identityHashCode(proxy)); } else if (methodName.equals("equals")) { return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE); } else if (methodName.equals("toString")) { return proxy.getClass().getName() + '@' + Integer.toHexString(proxy.hashCode()); } } return method.invoke(smartProxy, args); } @SuppressWarnings("unchecked") public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (isTerminated()) throw new IOException(thrown); Callable task = new MethodInvocationTask(this, proxy, method, args); return proxyExecutor.submit(task).get(timeout, unit); } private void terminate(Throwable e){ thrown = e; smartProxy = null; proxyExecutor.shutdown(); } private boolean isTerminated(){ if (smartProxy == null) return true; return false; } private static class Factory implements ThreadFactory{ private static final ThreadGroup tg = new ThreadGroup("IsolatedProxy"); { tg.setDaemon(true); tg.setMaxPriority(4); } private final ProxyIsolate proxy; Factory(ProxyIsolate spi){ proxy = spi; } public Thread newThread(Runnable r) { Thread t = new Thread(tg, r); t.setUncaughtExceptionHandler(new ExceptionHandler(proxy)); return t; } } private static class ExceptionHandler implements Thread.UncaughtExceptionHandler{ private final ProxyIsolate proxy; ExceptionHandler(ProxyIsolate spi){ proxy = spi; } public void uncaughtException(Thread t, Throwable e) { // For all other Exceptions we let the ExecutorService handle it. if ( e instanceof Error){ // Do we want to take different actions based on the error? proxy.terminate(e); } } } private static class UnmarshallProxyTask implements Callable{ private final MarshalledInstance mi; private final ClassLoader defaultLoader; private final boolean verifyCodebaseIntegrity; private final ClassLoader verifierLoader; private final Collection context; UnmarshallProxyTask(MarshalledInstance proxy, ClassLoader defaultLoader, boolean verifyCodebaseIntegrity, ClassLoader verifierLoader, Collection context) { mi = proxy; this.defaultLoader = defaultLoader; this.verifyCodebaseIntegrity = verifyCodebaseIntegrity; this.verifierLoader = verifierLoader; this.context = context; } public Object call() throws Exception { return mi.get(defaultLoader, verifyCodebaseIntegrity, verifierLoader, context); } } private static class MethodInvocationTask implements Callable { private final ProxyIsolate smartProxy; private final Object proxy; private final Method method; private final Object[] args; MethodInvocationTask(ProxyIsolate target, Object proxy, Method method, Object[] args){ smartProxy = target; this.proxy = proxy; this.method = method; this.args = args; } public Object call() throws Exception { return smartProxy.taskInvoke(proxy, method, args); } } }