Permalink
Browse files

Started writing documentation

  • Loading branch information...
1 parent f836752 commit e4afd216d19c1933df44b246482429e504168c8c @systay committed Nov 1, 2012
@@ -2,9 +2,13 @@
== Traversals ==
[WARNING]
-The Traversal REST Endpoint executes arbitrary Groovy code under the hood as part of the evaluators definitions. In hosted and open environments, this can constitute a security risk.
-In these case, consider using declarative approaches like <<cypher-query-lang>> or write your own server side plugin executing the
-interesting traversals with the Java API ( see <<server-plugins>> ) or secure your server, see <<security-server>>.
+The Traversal REST Endpoint executes arbitrary Javascript code under the hood as part of the evaluators definitions.
+In hosted and open environments, this can constitute a security risk. To minimize the exposure, you have three options.
+
+1) Consider using Cypher, which doesn't allow arbitrary code execution.
+2) Write your own server side plugin executing the interesting traversals with the Java API ( see <<server-plugins>> )
+3) Make sure you use the sand boxed script execution, as described in <<here>>
+
Traversals are performed from a start node.
The traversal is controlled by the URI and the body sent with the request.
@@ -67,3 +71,20 @@ include::paged-traverser-page-size.asciidoc[]
include::paged-traverser-timeout.asciidoc[]
+=== Sand boxing ===
+To protect the server from malicious code, the sand boxing keeps a list of acceptable classes. Any expression in the
+JavaScript code that returns objects, will have the objects typed as the closes acceptable class from this white list.
+
+So, if you do a .getClass() on an object, it will be cast to the closest white listed class. Since the Class<?> class
+only inherits from Object, it is cast as an Object. Only the methods available through the Object class are available to
+the JavaScript code.
+
+Here are the white listed classes:
+
+[snippet,java]
+----
+component=neo4j-server
+source=org/neo4j/server/scripting/UserScriptClassWhiteList.java
+tag=customConfiguredWrappingNeoServerBootstrapper
+classifier=sources
+----
@@ -153,6 +153,14 @@ rotation and +http://en.wikipedia.org/wiki/Common_Log_Format[Common Log Format]+
If logging is set up to use log files then the server will check that the log file directory exists and is writable. If
this check fails, then the server will not startup and wil report the failure another available channel like standard out.
+== Sand boxed script execution configuration ==
+Sand boxing of traversal descriptions can be turned off in the 'conf/neo4j-server.properties'. The default value is
+that sand boxing is turned on.
+
+[source]
+----
+org.neo4j.server.script.sandboxing.enabled=true
+----
== Other configuration options ==
@@ -160,6 +160,36 @@ public void shouldGetExpectedHitsWhenTraversingWithDescription()
getTraverseUriNodes( start ) ).entity();
expectNodes( entity, getNodes( "Root", "Mattias", "Peter", "Tobias" ) );
}
+
+ /**
+ * Sand boxed traversals.
+ *
+ * In this example, we make an attempt to get to the class loader, to wreck havoc. The server responds with a
+ * HTTP 400 status code, and tells you that you are not allowed to touch some classes.
+ */
+ @Documented
+ @Graph( {"Root knows Mattias"} )
+ @Test
+ public void shouldGetStatus400ForTryingToBreakTheSandBox()
+ throws PropertyValueException
+ {
+ Node start = getNode( "Root" );
+ List<Map<String, Object>> rels = new ArrayList<Map<String, Object>>();
+ rels.add( MapUtil.map( "type", "knows", "direction", "all" ) );
+ String description = JsonHelper.createJsonFrom( MapUtil.map(
+ "order",
+ "breadth_first",
+ "uniqueness",
+ "node_global",
+ "prune_evaluator",
+ MapUtil.map( "language", "javascript", "body", "position.length() > 10" ),
+ "return_filter",
+ MapUtil.map( "language", "javascript", "body",
+ "position.getClass().getClassLoader() != null" ),
+ "relationships", rels, "max_depth", 3 ) );
+
+ gen().expectedStatus( 400 ).payload( description ).post( getTraverseUriNodes( start ) ).entity();
+ }
/**
* Traversal returning nodes below a certain depth.
*
@@ -33,6 +33,7 @@
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
+import org.neo4j.server.rest.domain.EvaluationException;
import org.neo4j.server.rest.web.NodeNotFoundException;
public class OutputFormat
@@ -149,7 +150,7 @@ public void write(OutputStream output) throws IOException, WebApplicationExcepti
{
new WebApplicationException(notFound(e));
}
- if (e instanceof BadInputException)
+ if (e instanceof BadInputException || e instanceof EvaluationException )
{
throw new WebApplicationException(badRequest(e));
}
@@ -19,19 +19,11 @@
*/
package org.neo4j.server.scripting;
+import static java.util.Arrays.asList;
+
import java.util.HashSet;
import java.util.Set;
-import org.neo4j.graphdb.Direction;
-import org.neo4j.graphdb.DynamicRelationshipType;
-import org.neo4j.graphdb.Lock;
-import org.neo4j.graphdb.Node;
-import org.neo4j.graphdb.NotFoundException;
-import org.neo4j.graphdb.Path;
-import org.neo4j.graphdb.Relationship;
-import org.neo4j.graphdb.RelationshipType;
-import org.neo4j.graphdb.traversal.Evaluation;
-
/**
* A set of classes that we trust unknown entities to work with. These will be accessible to users that have remote access
* to a Neo4j database.
@@ -52,46 +44,38 @@
public static Set<String> getWhiteList()
{
- HashSet<String> safe = new HashSet<String>();
-
- // Core API concepts
-
- safe.add( Path.class.getName() );
- safe.add( Node.class.getName() );
- safe.add( Relationship.class.getName() );
- safe.add( RelationshipType.class.getName() );
- safe.add( DynamicRelationshipType.class.getName() );
- safe.add( Lock.class.getName() );
-
- safe.add( NotFoundException.class.getName() );
-
- // Traversal concepts
-
- safe.add( Direction.class.getName() );
- safe.add( Evaluation.class.getName() );
-
- // Java Core API
-
- safe.add( Object.class.getName() );
- safe.add( String.class.getName() );
- safe.add( Integer.class.getName() );
- safe.add( Long.class.getName() );
- safe.add( Float.class.getName() );
- safe.add( Double.class.getName() );
- safe.add( Boolean.class.getName() );
-
-
- // This is a work-around, since these are not supposed to be publicly available.
- // The reason we need to add it here is, most likely, that some methods in the API
- // returns these rather than the corresponding interfaces, which means our white list
- // checker doesn't know which interface to cast to (since there could be several). Instead
- // we allow users direct access to these classes for now.
- safe.add( "org.neo4j.kernel.impl.traversal.StartNodeTraversalBranch" );
- safe.add( "org.neo4j.kernel.impl.traversal.TraversalBranchImpl" );
- safe.add( "org.neo4j.kernel.impl.core.NodeProxy" );
-
-
- return safe;
+ String[] whites = {
+ // START SNIPPET: sandBoxingWhiteList
+ // Core API concepts
+ "org.neo4j.graphdb.Path",
+ "org.neo4j.graphdb.Node",
+ "org.neo4j.graphdb.Relationship",
+ "org.neo4j.graphdb.RelationshipType",
+ "org.neo4j.graphdb.DynamicRelationshipType",
+ "org.neo4j.graphdb.Lock",
+ "org.neo4j.graphdb.NotFoundException",
+
+ // Traversal concepts
+ "org.neo4j.graphdb.Direction",
+ "org.neo4j.graphdb.traversal.Evaluation",
+
+ // Java Core API
+ "java.lang.Object",
+ "java.lang.String",
+ "java.lang.Integer",
+ "java.lang.Long",
+ "java.lang.Float",
+ "java.lang.Double",
+ "java.lang.Boolean",
+
+ // Internals needed
+ "org.neo4j.kernel.impl.traversal.TraversalBranchImpl",
+ "org.neo4j.kernel.impl.core.NodeProxy",
+ "org.neo4j.kernel.impl.traversal.StartNodeTraversalBranch"
+ // END SNIPPET: sandBoxingWhiteList
+ };
+
+ return new HashSet<String>(asList(whites));
}
}
@@ -46,10 +46,7 @@ public static void doBullshitGlobalStateCrap()
public void shouldBeAbleToAccessWhiteListedThings() throws Exception
{
// Given
- String classThatShouldBeInaccessible = TestJavascriptSecurityRestrictions.class.getName();
-
- ScriptExecutor executor = new JavascriptExecutor(
- Evaluation.class.getName() + ".INCLUDE_AND_CONTINUE;" );
+ ScriptExecutor executor = new JavascriptExecutor( Evaluation.class.getName() + ".INCLUDE_AND_CONTINUE;" );
// When
Object result = executor.execute( null );
@@ -76,8 +73,7 @@ public void shouldNotBeAbleToImportUnsafeClasses() throws Exception
public void shouldNotBeAbleToUseReflectionToInstantiateThings() throws Exception
{
// Given
- ScriptExecutor executor = new JavascriptExecutor(
- Evaluation.class.getName() + ".getClass().getClassLoader();" );
+ ScriptExecutor executor = new JavascriptExecutor( Evaluation.class.getName() + ".getClass().getClassLoader();" );
// When
executor.execute( null );

0 comments on commit e4afd21

Please sign in to comment.