JEP 202: Nashorn Class Filter
Owner | Sundararajan Athijegannathan |
Type | Feature |
Scope | JDK |
Status | Closed / Delivered |
Release | 8u40 |
Component | core-libs / jdk.nashorn |
Discussion | nashorn dash dev at openjdk dot java dot net |
Effort | S |
Duration | S |
Reviewed by | Jim Laskey |
Endorsed by | Brian Goetz |
Created | 2014/05/22 06:51 |
Updated | 2017/05/17 00:43 |
Issue | 8043717 |
Summary
Provide fine-grained control over access to Java classes from JavaScript code.
Goals
-
Provide a Java class-access filtering interface,
ClassFilter
, that can be implemented by Java applications that use Nashorn. -
Nashorn will query a provided instance of the
ClassFilter
interface before accessing any Java class from a script in order to determine whether the access is allowed. This will occur whether or not a security manager is present. -
A script should not be able to subvert restrictions by a class filter in any way, not even by using Java's reflection APIs.
Non-goals
The API will not:
-
Filter the public methods or fields of any object that is exposed to scripts. For example, if a Nashorn-embedding application exposes a value that is a Java object, all public methods of object that will be invocable from scripts.
-
Filter individual methods or fields.
-
Make security managers redundant for scripts. Embedding applications should still turn on security management before evaluating scripts from untrusted sources. Class filtering alone will not provide a complete script "sandbox." Even if only untrusted scripts (with no additional Java classes) are executed, a security manager should still be utilized. Class filtering provides finer control beyond what a security manager provides. For example, a Nashorn-embedding application may prevent the spawning of threads from scripts or other resource-intensive operations that may be allowed by security manager.
-
Provide compatibility with Mozilla Rhino's
ClassShutter
s. Nashorn'sClassFilter
API will not have same package, class, or method names as that of the Mozilla Rhino engine. The proposed Nashorn API is only conceptually similar to the Rhino'sClassShutter
API.
Motivation
There are several global objects such as Packages
, java
, org
,
com
, javax
, javafx
, org
, net
, JavaImporter
and Java
that
provide easy access to Java classes from JavaScript code in Nashorn.
With a security manager on, the expected Java security policy is
enforced: Anonymous scripts are granted the same permissions as are
granted to untrusted classes, or else a script loaded from a URL is
granted the permissions associated with that URL.
When using Nashorn with the –no-java
option, the above global package
objects are not provided, effectively preventing all Java package and
class access from scripts. A script has either complete Java access,
subject to security restrictions, or else no access with –no-java
.
The Rhino JavaScript engine provides finer-grained access control via the
user defined ClassShutter
class. Rhino-embedding Java applications can
choose to expose a subset of Java classes to scripts. Nashorn should
provide similar fine-grained Java API.
Server-side JavaScript frameworks are an important target for the Nashorn script engine. Such frameworks may occasionally have to run scripts from untrusted sources and therefore limit access to Java APIs. While security-manager based sandboxing helps here, Nashorn-embedding server-side applications often need finer control. An API should make it possible to restrict Java class access to a subset of Java classes.
Description
A new interface, jdk.nashorn.api.scripting.ClassFilter
will be defined.
Nashorn-embedding applications such as server-side JavaScript frameworks
may choose to implement ClassFilter
. To provide a user-implemented
ClassFilter to Nashorn, the client application will have to use the
Nashorn-specific API to instantiate the Nashorn script engine.
New API added to class
jdk.nashorn.api.scripting.NashornScriptEngineFactory
:
/**
* Create a new Script engine initialized by given class filter.
*
* @return newly created script engine.
* @throws NullPointerException if {@code classFilter} is {@code null}
* @throws SecurityException
* if the security manager's {@code checkPermission}
* denies {@code RuntimePermission("nashorn.setConfig")}
*/
public ScriptEngine getScriptEngine(final ClassFilter classFilter)
/**
* Create a new Script engine initialized by given arguments.
*
* @param args arguments array passed to script engine.
* @param appLoader class loader to be used as script "application" class loader.
* @param classFilter class filter to use.
* @return newly created script engine.
* @throws NullPointerException if {@code args} or {@code classFilter} is {@code null}
* @throws SecurityException
* if the security manager's {@code checkPermission}
* denies {@code RuntimePermission("nashorn.setConfig")}
*/
public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter)
New interface jdk.nashorn.api.scripting.ClassFilter
:
public interface ClassFilter {
/**
* Should the Java class of the specified name be exposed to scripts?
* @param className is the fully qualified name of the java class being checked. This will not be null. Only non-array class names will be passed.
* @return true if the java class can be exposed to scripts false otherwise
*/
public boolean exposeToScripts(String className);
}
The Nashorn script interface to Java packages and classes is via the
Packages
object and the Java.type
function. The Packages
object
allows Java classes and packages be accessed via the familiar "dot-dot"
syntax. The Java.type
function accepts the string name of a
fully-qualified Java type and returns the corresponding Class
object.
Both of these APIs will check if there is a class filter set in the
Nashorn script engine. If a class filter is present then the interface
will query it to see if the class can be exposed to scripts. If the
filter returns false
then the Java.type
function will throw
ClassNotFoundException
and the Packages
API will treat a dotted name
as a package name rather than a class name.
Example:
var Vector = java.util.Vector;
var Thread = Java.type(`java.lang.Thread`);
If the class filter prevents access to java.util.Vector
and
java.lang.Thread
then in the first line java.util.Vector
will be
treated as a package name instead of being resolved as a Java class, and
in the second line the invocation of Java.type
will result in a
ClassNotFoundException
being thrown.
If a security manager is present then Nashorn allows a script to use the
Java reflection APIs (i.e., java.lang.reflect
and java.lang.invoke
)
only if the script has the nashorn.javaReflection
run-time permission.
If a class filter is present then Nashorn will prevent access to
reflective APIs even when a security manager is not present. It does not
make sense to use a class filter if reflection is available, because a
script can use the Class.forName(String)
method to circumvent the class
filter.
Testing
There are over 1,000 Nashorn script tests in the Nashorn repository.
There are tests accessing the javax.script
API as well as the
Nashorn-specific APIs in the jdk.nashorn.api.scripting
package. The
latter will be extended to include class-filter tests.
Risks and Assumptions
The new API will be added to the existing jdk.nashorn.api.scripting
package. Users will have to use this non-standard, JDK-specific API in
order to implement class filters.