How To Catch A ClassNotFoundException By Roger Keays, 13 April 2014

HTTP request from spammers trying to exploit our commenting system is causing a ClassNotFoundException deep in the JSF / Java code. Specifically, spammers are sending serialized objects in the javax.jsf.ViewState parameter for classes that no longer exist in our system. The resulting exception is this:

java.lang.ClassNotFoundException: ox.cms.designer.UIMenu$MenuLayout at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:248) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:247) at com.sun.faces.renderkit.ApplicationObjectInputStream.resolveClass(ApplicationObjectInputStream.java:95) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495) at java.io.ObjectInputStream.readEnum(ObjectInputStream.java:1685) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1325) at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1666) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1322) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350) at java.util.HashMap.readObject(HashMap.java:1030) at sun.reflect.GeneratedMethodAccessor12161.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1848) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350) at com.sun.faces.renderkit.ClientSideStateHelper.doGetState(ClientSideStateHelper.java:255) at com.sun.faces.renderkit.ClientSideStateHelper.getState(ClientSideStateHelper.java:198) at com.sun.faces.renderkit.ResponseStateManagerImpl.getState(ResponseStateManagerImpl.java:100) at com.sun.faces.application.view.StateManagementStrategyImpl.restoreView(StateManagementStrategyImpl.java:224) at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:188) at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:123) at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:453) at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:142) at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:303) at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:303) at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:192) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)

Nasty stuff.

The problem gets worse because ClassNotFoundException is a checked exception (although somehow the URLClassLoader gets to ignore it), so we can't just put a catch block in our filter because the compiler complains that the exception is never thrown.

Fortunately there is a simple, if not slightly ugly solution:

try { // this line allows us to catch a ClassNotFoundException if (false) Class.forName("java.lang.Class"); chain.doFilter(request, response); } catch (ClassNotFoundException cnfe) { Log.warning(cnfe.getMessage() + " (spam)"); }

So much for checked exceptions.

About Roger Keays