Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Mended broken link

...

This noncompliant code example incorporates untrusted user input in a JavaScript statement that is responsible for printing the input. An attacker can enter specially crafted arguments in an attempt to inject malicious JavaScript. The firstName string contains JavaScript code that can create or overwrite an existing file on the system running the vulnerable Java code.

Code Block
bgColor#FFCCCC

// Windows-based target's file path is being used
String firstName = "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(); } // "; 
	  
evalScript(firstName);

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

...

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 IDS01to 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 before comparing with their equivalent forms.

A complementary policy is to create a secure sandbox using a security manager. (See SEC58-J. Create a secure sandbox using a Security Manager.) This approach is akin to the one discussed in the first compliant solution of VOID IDS10-J. Prevent XML external entity attacks. 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 VOID SEC00-J. Avoid granting excess privileges for more details on the two-argument form.

Code Block
bgColor#ccccff

// First sanitize firstName (modify if the name may include special characters)

if(!firstName.matches("[\\w]*")) { // String does not match whitelisted characters
  throw new IllegalArgumentException();
} 

// 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);
} catch(PrivilegedActionException pae) {    	
  // Handle
}       

...