You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 73 Next »

Code injection can occur when untrusted input is injected into dynamically constructed code. The javax.script package both provides an API of interfaces and classes that define Java Scripting Engines and also defines a framework for the use of those interfaces and classes in Java code. An obvious example is the use of JavaScript from Java code.  Misuse of the javax.script API permits an attacker to execute arbitrary code on the target system. Such errors are dangerous because violations of secure coding practices in dynamically generated code cannot be detected in advance through static analysis.

This guideline is a specific instance of IDS00-J. Sanitize untrusted data passed across a trust boundary.

Noncompliant Code Example

This noncompliant code example incorporates untrusted user input in a JavaScript statement that is responsible for printing the input.

private static void evalScript(String firstName) throws ScriptException {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("javascript");
  engine.eval("print('"+ firstName + "')");	
}

An attacker can enter a specially crafted argument in an attempt to inject malicious JavaScript. This example shows a malicious string that contains JavaScript code that can create or overwrite an existing file on a Windows system running the vulnerable Java code.

dummy\');
var bw = new JavaImporter(java.io.BufferedWriter); 
var fw = new JavaImporter(java.io.FileWriter); 
with(fw) with(bw) { 
   bwr = new BufferedWriter(new FileWriter(\"c://somepath//somefile.txt\"));
   bwr.write(\"some text\"); bwr.close();
}
// ; 

The script prints dummy and writes some text to somefile.txt behind the scenes.

Compliant Solution (Whitelisting)

The best defense against code injection vulnerabilities is to avoid including executable user input in code. When dynamic code requires user input, that input must be sanitized. For example, a top-level method could ensure that the string firstName contains only valid, whitelisted characters. Refer to IDS00-J. Sanitize untrusted data passed across a trust boundary for more details. If special characters are allowed in the name, they must be escaped and normalized before comparing with their equivalent forms for the purpose of input validation. This compliant solution uses whitelisting to prevent unsanitized input from being interpreted by the scripting engine.

private static void evalScript(String firstName) throws ScriptException {
  // First sanitize firstName (modify if the name may include special characters)
  if (!firstName.matches("[\\w]*")) { // String does not match whitelisted characters
    throw new IllegalArgumentException();
  } 

  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("javascript");
  engine.eval("print('"+ firstName + "')");	
}

Compliant Solution (Secure Sandbox)

An alternative approach is to create a secure sandbox using a security manager. (See SEC60-JG. Create a secure sandbox using a Security Manager.)  The application should not allow the script to execute arbitrary commands including, for example, querying the local file system. The two-argument form of doPrivileged() can be used to lower privileges when the application must operate with higher privileges but the scripting engine must not. The RestrictedAccessControlContext strips the permissions granted in the default policy file by reducing the permissions granted to the newly created protection domain. The effective permissions are the intersection of the permissions of the newly created protection domain and the systemwide security policy. Refer to SEC50-JG. Avoid granting excess privileges for more details on the two-argument form.

This compliant solution illustrates the use of an AccessControlContext in the two-argument form of doPrivileged().

class ACC {

  private static class RestrictedAccessControlContext {
      private static final AccessControlContext INSTANCE;
      static {	      
          INSTANCE = new AccessControlContext(new ProtectionDomain[] {
                  new ProtectionDomain(null, null) // no permissions
              });
      }
  }

  // Restrict permission using the two-argument form of doPrivileged()
  try {
    AccessController.doPrivileged(new PrivilegedExceptionAction() {
      public Object run() throws ScriptException {
        engine.eval("print('"+ firstName + "')");		
        return null;
      }    	
    }, RestrictedAccessControlContext.INSTANCE); // From nested class
  } catch(PrivilegedActionException pae) {    	
    // Handle
  }       

This approach could be combined with whitelisting for extra security.

Applicability

Failure to prevent code injection can result in the execution of arbitrary code.

Bibliography

[API 2011] Package javax.script
[OWASP 2008] Code injection in Java


  • No labels