Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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

Code Block
bgColor#FFCCCC
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 vulnerable system.:

Code Block
bgColorffffcc
languagejavascript
dummy\');
var bw = new JavaImporter(java.io.BufferedWriter); 
var fw = new JavaImporter(java.io.FileWriter); 
with(fw) with(bw) { 
   bwr = new BufferedWriter(new FileWriter(\"config.cfg"));
   bwr.write(\"some text\"); bwr.close();
}
// ; 

...

The best defense against code injection vulnerabilities is to prevent inclusion of 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 must be permitted in the name, they must be escaped and normalized before comparison 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.:

Code Block
bgColor#ccccff
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 + "')");	
}

...

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

Code Block
bgColor#ccccff
class ACC {
  private static class RestrictedAccessControlContext {
    private static final AccessControlContext INSTANCE;
  
    static {
      INSTANCE = new AccessControlContext(
               new ProtectionDomain[] { new ProtectionDomain(null, null) // No permissions
               });
    }
  }
  
  private static void evalScript(final String firstName)
            throws ScriptException {
    ScriptEngineManager manager = new ScriptEngineManager();
    final ScriptEngine engine = manager.getEngineByName("javascript");
    // Restrict permission using the two-argument form of doPrivileged()
    try {
      AccessController.doPrivileged(
        new PrivilegedExceptionAction<Object>() {
                        
          public Object run() throws ScriptException {
            engine.eval("print('" + firstName + "')");
            return null;
          }
        }, RestrictedAccessControlContext.INSTANCE); // From nested class
                                                                    
    } catch (PrivilegedActionException pae) {
      // Handle
    }
  }
}

...