Author: wglass Date: Mon Oct 9 20:43:45 2006 New Revision: 454595 URL: http://svn.apache.org/viewvc?view=rev&rev=454595 Log: Offer optional SecureUberspector which prohibits method calls on 'dangerous' classes like Class and ClassLoader.
Added: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorControl.java (with props) jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorImpl.java (with props) jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureUberspector.java (with props) jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/SecureIntrospectionTestCase.java (with props) Modified: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/RuntimeServicesAware.java jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java jakarta/velocity/engine/trunk/xdocs/changes.xml Modified: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java?view=diff&rev=454595&r1=454594&r2=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java (original) +++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java Mon Oct 9 20:43:45 2006 @@ -336,12 +336,21 @@ */ public static final String ENCODING_DEFAULT = "ISO-8859-1"; - /** * key name for uberspector */ public static final String UBERSPECT_CLASSNAME = "runtime.introspector.uberspect"; + /** + * A comma separated list of packages to restrict access to in the SecureIntrospector + */ + public static final String INTROSPECTOR_RESTRICT_PACKAGES = "introspector.restrict.packages"; + + /** + * A comma separated list of classes to restrict access to in the SecureIntrospector + */ + public static final String INTROSPECTOR_RESTRICT_CLASSES = "introspector.restrict.classes"; + /** * The <code>parser.pool.class</code> property * specifies the name of the [EMAIL PROTECTED] Modified: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java?view=diff&rev=454595&r1=454594&r2=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java (original) +++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java Mon Oct 9 20:43:45 2006 @@ -304,6 +304,11 @@ ((UberspectLoggable) uberSpect).setLog(getLog()); } + if (uberSpect instanceof RuntimeServicesAware) + { + ((RuntimeServicesAware) uberSpect).setRuntimeServices(this); + } + uberSpect.init(); } else Modified: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties?view=diff&rev=454595&r1=454594&r2=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties (original) +++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties Mon Oct 9 20:43:45 2006 @@ -160,9 +160,38 @@ # ---------------------------------------------------------------------------- # PLUGGABLE INTROSPECTOR # ---------------------------------------------------------------------------- -# Allows alternative introspection and all that can of worms brings +# Allows alternative introspection and all that can of worms brings. # ---------------------------------------------------------------------------- runtime.introspector.uberspect = org.apache.velocity.util.introspection.UberspectImpl + + +# ---------------------------------------------------------------------------- +# SECURE INTROSPECTOR +# ---------------------------------------------------------------------------- +# If selected, prohibits methods in certain classes and packages from being +# accessed. +# ---------------------------------------------------------------------------- + +introspector.restrict.packages = java.lang.reflect + +# The two most dangerous classes + +introspector.restrict.classes = java.lang.Class +introspector.restrict.classes = java.lang.ClassLoader + +# Restrict these for extra safety + +introspector.restrict.classes = java.lang.Compiler +introspector.restrict.classes = java.lang.InheritableThreadLocal +introspector.restrict.classes = java.lang.Package +introspector.restrict.classes = java.lang.Process +introspector.restrict.classes = java.lang.Runtime +introspector.restrict.classes = java.lang.RuntimePermission +introspector.restrict.classes = java.lang.SecurityManager +introspector.restrict.classes = java.lang.System +introspector.restrict.classes = java.lang.Thread +introspector.restrict.classes = java.lang.ThreadGroup +introspector.restrict.classes = java.lang.ThreadLocal Modified: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/RuntimeServicesAware.java URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/RuntimeServicesAware.java?view=diff&rev=454595&r1=454594&r2=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/RuntimeServicesAware.java (original) +++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/RuntimeServicesAware.java Mon Oct 9 20:43:45 2006 @@ -30,7 +30,7 @@ public interface RuntimeServicesAware { /** - * Initialize the EventHandler. + * Store the RuntimeServices before the object is initialized.. * @param rs * @throws Exception */ Modified: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java?view=diff&rev=454595&r1=454594&r2=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java (original) +++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java Mon Oct 9 20:43:45 2006 @@ -62,7 +62,7 @@ /** * The Log we use */ - private Log log = null; + protected Log log = null; /** * @param log Added: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorControl.java URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorControl.java?view=auto&rev=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorControl.java (added) +++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorControl.java Mon Oct 9 20:43:45 2006 @@ -0,0 +1,38 @@ +package org.apache.velocity.util.introspection; + +/* + * Copyright 2000-2006 The Apache Software Foundation. + * + * Licensed 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. + */ + +/** + * Interface used to determine which methods are allowed to be executed. + * + * @author <a href="Will Glass-Husain">[EMAIL PROTECTED]</a> + * @version $Id$ + */ +public interface SecureIntrospectorControl +{ + + /** + * Determine which methods and classes to prevent from executing. + * + * @param o object for which method is being called + * @param method method being called. This may be null in the case of a call to iterator, get, or set method + * + * @return true if method may be called on object + */ + public boolean checkObjectExecutePermission(Class clazz, String method); + +} \ No newline at end of file Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorControl.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorControl.java ------------------------------------------------------------------------------ svn:keywords = Id Author Date Revision Added: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorImpl.java URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorImpl.java?view=auto&rev=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorImpl.java (added) +++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorImpl.java Mon Oct 9 20:43:45 2006 @@ -0,0 +1,135 @@ +package org.apache.velocity.util.introspection; + +/* + * Copyright 2001-2006 The Apache Software Foundation. + * + * Licensed 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. + */ + +import java.lang.reflect.Method; + +import org.apache.velocity.runtime.log.Log; + +/** + * <p>Prevent "dangerous" classloader/reflection related calls. Use this + * introspector for situations in which template writers are numerous + * or untrusted. Specifically, this introspector prevents creation of + * arbitrary objects and prevents reflection on objects. + * + * <p>See documentation of checkObjectExecutePermission() for + * more information on specific classes and methods blocked. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Will Glass-Husain</a> + * @version $Id$ + */ +public class SecureIntrospectorImpl extends Introspector implements SecureIntrospectorControl +{ + private String[] badClasses; + private String[] badPackages; + + public SecureIntrospectorImpl(String[] badClasses, String[] badPackages, Log log) + { + super(log); + this.badClasses = badClasses; + this.badPackages = badPackages; + } + + + public Method getMethod(Class c, String name, Object[] params) throws Exception + { + if (!checkObjectExecutePermission(c,name)) + { + log.warn ("Cannot retrieve method " + name + + " from object of class " + c.getName() + + " due to security restrictions."); + return null; + + } + else + { + return super.getMethod(c, name, params); + } + } + + /** + * Determine which methods and classes to prevent from executing. Always blocks + * methods wait() and notify(). Always allows methods on Number, Boolean, and String. + * Prohibits method calls on classes related to reflection and system operations. + * For the complete list, see the properties <code>introspector.restrict.classes</code> + * and <code>introspector.restrict.packages</code>. + * + * @see org.apache.velocity.util.introspection.SecureIntrospectorControl#checkObjectExecutePermission(java.lang.Class, java.lang.String) + */ + public boolean checkObjectExecutePermission(Class clazz, String method) + { + /** + * check for wait and notify + */ + if ( (method != null) && (method.equals("wait") || method.equals("notify")) ) + { + return false; + } + + /** + * Always allow the most common classes - Number, Boolean and String + */ + else if (java.lang.Number.class.isAssignableFrom(clazz)) + { + return true; + } + + else if (java.lang.Boolean.class.isAssignableFrom(clazz)) + { + return true; + } + + else if (java.lang.String.class.isAssignableFrom(clazz)) + { + return true; + } + + /** + * check the classname (minus any array info) + * whether it matches disallowed classes or packages + */ + String className = clazz.getName(); + if (className.startsWith("[L") && className.endsWith(";")) + { + className = className.substring(2,className.length() - 1); + } + + String packageName; + int dotPos = className.lastIndexOf('.'); + packageName = (dotPos == -1) ? "" : className.substring(0,dotPos); + + int sz = badPackages.length; + for (int i = 0; i < sz; i++) + { + if (packageName.equals(badPackages[i])) + { + return false; + } + } + + sz = badClasses.length; + for (int i = 0; i < sz; i++) + { + if (className.equals(badClasses[i])) + { + return false; + } + } + + return true; + } +} Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureIntrospectorImpl.java ------------------------------------------------------------------------------ svn:keywords = Id Author Date Revision Added: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureUberspector.java URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureUberspector.java?view=auto&rev=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureUberspector.java (added) +++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureUberspector.java Mon Oct 9 20:43:45 2006 @@ -0,0 +1,98 @@ +package org.apache.velocity.util.introspection; + +/* + * Copyright 2001-2006 The Apache Software Foundation. + * + * Licensed 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. + */ + +import java.util.Iterator; + +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.util.RuntimeServicesAware; + +/** + * Use a custom introspector that prevents classloader related method + * calls. Use this introspector for situations in which template + * writers are numerous or untrusted. Specifically, this introspector + * prevents creation of arbitrary objects or reflection on objects. + * + * <p>To use this introspector, set the following property: + * <pre> + * runtime.introspector.uberspect = org.apache.velocity.util.introspection.SecureUberspector + * </pre> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Will Glass-Husain</a> + * @version $Id$ + */ +public class SecureUberspector extends UberspectImpl implements RuntimeServicesAware +{ + RuntimeServices runtimeServices; + + public SecureUberspector() + { + super(); + } + + /** + * init - generates the Introspector. As the setup code + * makes sure that the log gets set before this is called, + * we can initialize the Introspector using the log object. + */ + public void init() + { + String [] badPackages = runtimeServices.getConfiguration() + .getStringArray(RuntimeConstants.INTROSPECTOR_RESTRICT_PACKAGES); + + String [] badClasses = runtimeServices.getConfiguration() + .getStringArray(RuntimeConstants.INTROSPECTOR_RESTRICT_CLASSES); + + introspector = new SecureIntrospectorImpl(badClasses, badPackages, log); + } + + /** + * The superclass method does not call the introspector, so the + * secure version needs to check for execute permission. + */ + public Iterator getIterator(Object obj, Info i) + throws Exception + { + if ((obj != null) && + !((SecureIntrospectorControl) introspector) + .checkObjectExecutePermission(obj.getClass(),null)) + { + log.warn ("Cannot retrieve iterator from object of class " + + obj.getClass().getName() + + " due to security restrictions."); + return null; + + } + else + { + return super.getIterator(obj,i); + } + } + + /** + * Store the RuntimeServices before the object is initialized.. + * @param rs + * @throws Exception + */ + public void setRuntimeServices(RuntimeServices rs) throws Exception + { + this.runtimeServices = rs; + } + + +} Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureUberspector.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/SecureUberspector.java ------------------------------------------------------------------------------ svn:keywords = Id Author Date Revision Modified: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java?view=diff&rev=454595&r1=454594&r2=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java (original) +++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java Mon Oct 9 20:43:45 2006 @@ -50,7 +50,7 @@ /** * Our runtime logger. */ - private Log log; + protected Log log; /** * the default Velocity introspector Added: jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/SecureIntrospectionTestCase.java URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/SecureIntrospectionTestCase.java?view=auto&rev=454595 ============================================================================== --- jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/SecureIntrospectionTestCase.java (added) +++ jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/SecureIntrospectionTestCase.java Mon Oct 9 20:43:45 2006 @@ -0,0 +1,154 @@ +package org.apache.velocity.test; + +/* + * Copyright 2000-2006 The Apache Software Foundation. + * + * Licensed 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. + */ + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.util.introspection.SecureUberspector; + +/** + * Checks that the secure introspector is working properly. + * + * @author <a href="Will Glass-Husain">[EMAIL PROTECTED]</a> + * @version $Id$ + */ +public class SecureIntrospectionTestCase extends BaseTestCase +{ + + /** + * Default constructor. + */ + public SecureIntrospectionTestCase(String name) + { + super(name); + } + + public static Test suite() + { + return new TestSuite(SecureIntrospectionTestCase.class); + } + + + private String [] badTemplateStrings = + { + "$test.Class.Name", + "$test.Class.Methods", + "$test.Class.ClassLoader", + "$test.Class.ClassLoader.loadClass('java.util.HashMap').newInstance().size()" + }; + + private String [] goodTemplateStrings = + { + "#set($test.Property = 'abc')$test.Property", + "$test.aTestMethod()" + }; + + /** + * Test to see that "dangerous" methods are forbidden + */ + public void testBadMethodCalls() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, SecureUberspector.class.getName()); + ve.init(); + + /* + * all of the following method calls should not work + */ + doTestMethods(ve, badTemplateStrings, false); + } + + /** + * Test to see that "dangerous" methods are forbidden + */ + public void testGoodMethodCalls() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, SecureUberspector.class.getName()); + ve.init(); + + /* + * all of the following method calls should not work + */ + doTestMethods(ve, goodTemplateStrings, true); + } + + private void doTestMethods(VelocityEngine ve, String[] templateStrings, boolean shouldeval) + { + Context c = new VelocityContext(); + c.put("test", this); + + try + { + for (int i=0; i < templateStrings.length; i++) + { + if (shouldeval && !doesStringEvaluate(ve,c,templateStrings[i])) + { + fail ("Should have evaluated: " + templateStrings[i]); + } + + if (!shouldeval && doesStringEvaluate(ve,c,templateStrings[i])) + { + fail ("Should not have evaluated: " + templateStrings[i]); + } + } + + } + catch (Exception e) + { + fail(e.toString()); + } + } + + private boolean doesStringEvaluate(VelocityEngine ve, Context c, String inputString) throws ParseErrorException, MethodInvocationException, ResourceNotFoundException, IOException + { + Writer w = new StringWriter(); + ve.evaluate(c, w, "foo", inputString); + String result = w.toString(); + return !result.equals(inputString); + } + + private String testProperty; + public String getProperty() + { + return testProperty; + } + + public int aTestMethod() + { + return 1; + } + + public void setProperty(String val) + { + testProperty = val; + } +} Propchange: jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/SecureIntrospectionTestCase.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/SecureIntrospectionTestCase.java ------------------------------------------------------------------------------ svn:keywords = Id Author Date Revision Modified: jakarta/velocity/engine/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/xdocs/changes.xml?view=diff&rev=454595&r1=454594&r2=454595 ============================================================================== --- jakarta/velocity/engine/trunk/xdocs/changes.xml (original) +++ jakarta/velocity/engine/trunk/xdocs/changes.xml Mon Oct 9 20:43:45 2006 @@ -24,6 +24,12 @@ <body> <release version="1.5-dev" date="in Subversion"> + <action type="add" dev="wglass" issue="VELOCITY-179"> + New, optional SecureIntrospector prohibits methods that involve manipulation of classes, classloaders + or reflection objects. Use this introspector to secure Velocity against a risk of + template writers using reflection to perform malicious acts. + </action> + <action type="fix" dev="henning" issue="VELOCITY-458"> Removed Serializable from InternalContextBase, because one of the members is not serializable anyway so this never worked (Found by Findbugs). </action> --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]