Code injection results from untrusted input being injected into dynamically constructed code. The javax.script
package provides utilities to use various scripting engines from Java code. Misuse of these utilities 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.
Noncompliant Code Example
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 | ||
---|---|---|
| ||
// 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 + "')"); } |
Compliant Solution
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 before comparing with their equivalent forms.
...
Code Block | ||
---|---|---|
| ||
class ACC { private static class RestrictedAccessControlContext { private static final AccessControlContext INSTANCE; static { INSTANCE = new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, null) // no permissions }); } } // 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); // From nested class } catch(PrivilegedActionException pae) { // Handle } |
Risk Assessment
Failure to prevent code injection can result in the execution of arbitrary code.
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
IDS52IDS51-JJG | high | likely | medium | P18 | L1 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
Bibliography
[API 2006] Package javax.script
[OWASP 2008] Code injection in Java
...
IDS53-JG. Prevent LDAP injection 00. Input Validation and Data Sanitization (IDS) VOID IDS53-J. Account for supplementary and combining characters in globalized code