Secure Coding in Java SE Application
- Develop code that mitigates security threats such as denial of service, code injection, input validation and ensure data integrity
- Secure resource access including filesystems, manage policies and execute privileged code
Rule(s)
- Attacks can be based on code injection. Straightforward way is the use of JavaScript. Please note that in the two following examples, JavaScript code may easily be encrypted, and later decrypted just before execution
- While first example is based on JavaScript built-in interpreter (Nashorn Engine is still in in Java 11, but it is removed from future releases), second example loads a script file be to executed by Node.js, provided that Node.js is installed
Example (
./Attack_.js
JavaScript file) Security.Java.zipvar attack = function (name) { return "Attack from " + name; }
Example (Java) Security.Java.zip
try { javax.script.ScriptEngineManager manager = new javax.script.ScriptEngineManager(); javax.script.ScriptEngine engine = manager.getEngineByName("JavaScript"); engine.eval(new java.io.FileReader("./Attack_.js")); javax.script.Invocable invocable = (javax.script.Invocable) engine; Object result = invocable.invokeFunction("attack", "Franck"); System.out.println(result); // "Attack from Franck" } catch (Exception e) { /* ... */ }
Example (
./Attack.js
JavaScript file) Security.Java.zipconst fs = require('fs'); try { // 'w' flag makes sure the file is created if not existing. If the file exists then 'w' overwrites it with a new file, overriding its content: fs.openSync('./File.txt', 'w'); } catch (e) { // console.error(e); }
Example (Java) Security.Java.zip
// String[] command = {"Get-Command node"}; // Window-specific, does not work... // Test whether Node.js is installed or not: // String[] command = {"C:\\Program Files\\nodejs\\node.exe", "--version"}; String[] command = {"C:\\Program Files\\nodejs\\node.exe", "Attack.js"}; // Window-specific... try { Process p = Runtime.getRuntime().exec(command); if (p.waitFor() == 0) { try ( java.io.BufferedReader input = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()))) { String content; while ((content = input.readLine()) != null) { System.out.println("Node.js ver. is " + content); } } } else { try ( java.io.BufferedReader input = new java.io.BufferedReader(new java.io.InputStreamReader(p.getErrorStream()))) { String content; while ((content = input.readLine()) != null) { System.err.println("Err: " + content); } } } } catch (InterruptedException | java.io.IOException ieioe) { System.err.println("Runtime.getRuntime().exec(command): " + ieioe.getClass().getSimpleName() + ": " + ieioe.getMessage()); }
Rule(s)
- Java supports security policies that may be extended on demand to execute “privileged” code using
java.security.PrivilegedAction<Void>
Example Security.Java.zip
public class Critical_operation implements java.security.PrivilegedAction<Void> { @Override public Void run() { // Do something special... return null; } } … // '*' means all files in current directory: java.io.FilePermission file_permission = new java.io.FilePermission("*", "read,write,execute,delete"); try { java.security.AccessController.getContext().checkPermission(file_permission); // Current security policy... } catch (java.security.AccessControlException ace) { System.err.println("Such file permission is unauthorized: " + file_permission.getActions()); } Critical_operation co = new Critical_operation(); // 'co' is run in privileged mode: java.security.AccessController.doPrivileged(co); java.security.AccessController.doPrivileged((java.security.PrivilegedAction<Void>) () -> { System.out.println("Run in privileged mode... " + System.getProperty("user.name")); return null; });
Rule(s)
- Introspection is the ability of a programming language to be self-described. In practice, types become at run-time (leaf) objects of a given meta-type.
java.lang.Class<T>
plays this role in Java- Introspection is subject to security issues taking account the possibility of executing
private
methods ☛Example
Class<?> class_of_Temperature = Temperature.class; // Access from '.class' Java native operator Class<?> class_of_Temperature_unit = Temperature.Temperature_unit.class; assert (class_of_Temperature == class_of_Temperature_unit.getEnclosingClass()); Temperature ambient_temperature = new Temperature(18.F, Temperature.Temperature_unit.Celsius); assert (class_of_Temperature == ambient_temperature.getClass()); // Access from 'getClass' Java method in 'java.lang.Class<T>'
Rule(s)
- The
java.lang.reflect
API offers a powerful support to dynamically handle runtime resources. Couterparts of this support are possible security flaws- As an illustration,
java.lang.reflect.Method
meta-class allows the execution of introspected methods; related exceptions may be raised to control unsecure usage (e.g., invoking private methods)Example Introspection.Java.zip
java.lang.reflect.Method methods[] = ambient_temperature.getClass().getMethods(); for (java.lang.reflect.Method method : methods) { Class<?>[] types_of_parameters = method.getParameterTypes(); Object arguments[] = null; if (method.getName().equals("toString") && method.isVarArgs() == false && method.getParameterTypes().length == 0) { try { System.out.println("Calling 'toString' by introspection on 'ambient_temperature': " + method.invoke(ambient_temperature, arguments)); } catch (IllegalAccessException | IllegalArgumentException | java.lang.reflect.InvocationTargetException e) { System.err.println(e.getMessage()); } } }