Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: separated security checking from runtime requirements

...

Many of the Java SE APIs use security manager checks by default before performing sensitive operations. For example, the constructor of class java.io.FileInputStream throws a SecurityException if the caller does not have the permission to read a file. Note that the documentation of some APIs, for example the java.io.FileReader class, may not contain information about the SecurityException because it is a subclass of RuntimeException; it is not mandatory to document runtime exceptions. Installing a security manager from the command line or programatically helps create a default sandbox that denies such permissions if the security policy file in effect does not grant thempermit the actions.

Noncompliant Code Example

The worst form of non-compliance is not using the the security manager or the AccessController mechanism. Even when used, there can be cases where the appropriate checks are not installed. This noncompliant code example passes a null value to the setSecurityManager method that is responsible for setting the expected instance of SecurityManager. As a result, no security manager will be installed (assuming that the security manager is not installed from the command line either).

Code Block
bgColor#FFcccc

try {
  System.setSecurityManager(null);
} catch (SecurityException se) { 
  // cannot set security manager, log to file
}

Noncompliant Code Example

In this noncompliant code example, none of the check* methods have been used even though a custom security manager has been set programatically.

Code Block
bgColor#FFcccc

try {
  System.setSecurityManager(new CustomSecurityManager("password here"));
} catch (SecurityException se) { 
  // cannot set security manager, log to file
}

Compliant Solution

This compliant solution demonstrates how a custom SecurityManager class called CustomSecurityManager can be activated by invoking its constructor with a password. Various check* methods defined within the class can then be invoked to perform access checks. In this case, checkRead() succeeds if the current protection domain's file permission name tallies with that of the file name argument for the read action.

Code Block
bgColor#ccccff

try {
  System.setSecurityManager(new CustomSecurityManager("password here"));
  SecurityManager sm = System.getSecurityManager();
  if(sm != null) {  //check if file can be read
    sm.checkRead("/temp/tempFile");
  } 
} catch (SecurityException se) { 
  // cannot set security manager, log to file
}

Compliant Solution

An alternative is to use the default security manager instead of a custom one, as shown below. To do this, change the active instance to java.lang.SecurityManager (invoke setSecurityManager() with the argument new SecurityManager()).

Code Block
bgColor#ccccff

try {
  System.setSecurityManager(new SecurityManager());
  SecurityManager sm = System.getSecurityManager();

  if(sm != null) {  //check if file can be read
    sm.checkRead("/temp/tempFile");
  } 
} catch (SecurityException se) { 
  // cannot set security manager, log to file
}

Compliant Solution

The check*() methods detailed in the preceding compliant solutions were more prevalent in older Java SE versions. Two methods, checkPermission(Permission perm) and checkPermission(Permission perm, Object context) were added in J2SE 1.2. The motivations for this change were manifold:

  • The checkPermission methods eliminated the need for hardcoding names of the checks in the call.
  • They used only one copy of the complicated algorithms and code for examining the Java runtime by using a common checkPermission method.
  • Newer permissions for resources could be easily added by encapsulating them in a new Permission subclass.

The single argument checkPermission method uses the context of the currently executing environment to perform the checks. If the context has the permission as defined in the local policy file, the check succeeds, otherwise a SecurityException is thrown.

This compliant solution exemplifies the single argument checkPermission methoddoes not install the security manager from the command line (assuming that the security manager is not set programatically).

Code Block
bgColor#ccccff

try {
  System.setSecurityManager(new CustomSecurityManager("password here"));
  SecurityManager sm = System.getSecurityManager();
  if(sm != null) {  //check if file can be read
    FilePermission perm = new FilePermission("/temp/tempFile", "read");
    sm.checkPermission(perm);
  } 
} catch (SecurityException se) { System.out.println("Not allowed"); }

Sometimes the security check code exists in one context (such as a worker thread) while the check has to be conducted on a different context, such as another thread. The two argument checkPermission is used in this case. It accepts an AccessControlContext instance as the context argument. The effective permissions are not computed as the intersection of the permissions of the two contexts and consist of the permissions of the context argument only.

Both the single and double argument checkPermission methods defer to the single argument java.security.AccessController.checkPermission(Permission perm) method. When invoked directly, this method operates only on the current execution context and as a result does not supersede the security manager's two argument version.

There is also another (cleaner and preferable) way to handle the security check from a different context. This is accomplished by taking a snapshot of the current execution context using the java.security.AccessController.getContext() method that returns an AccessControlContext object. The AccessControlContext class itself defines a checkPermission method that encapsulates a context instead of accepting the current executing context as a parameter. This is shown below.

#FFcccc

java LocalJavaApp
Code Block
bgColor#ccccff

// Take the snapshot of the required context, store in acc and pass it to another context
AccessControlContext acc = AccessController.getContext(); 


// Accept acc in another context and invoke checkPermission() on it
acc.checkPermission(perm); 

Compliant Solution

Any Java program (bean, servlet or application) can instantiate a SecurityManager. However, for applications programatically in the absence of a default, global security manager that does not permit this operation. Applications designed to run locally , an explicit flag must be set to enforce the SecurityManager policy whenever the security manager is not set programatically. Sometimes this is desired when applications must not install custom security managers but only can use a default global security manager by explicitly setting a flag on the command line while invoking the application. The command line option is usually desired when applications must be prohibited from installing custom security managers programatically and must obey the default global security policy . The under all circumstances. This compliant solution installs the default security manager can be installed using the flags as follows: appropriate command line flags. The security policy file grants permissions to the application for allowable actions.

Code Block
bgColor#ccccff
java -Djava.security.manager -Djava.security.policy=policyURL LocalJavaApp

Even a custom security manager can be made the default and enforced globally from the command line by specifying its absolute path location immediately after an equal-to sign that must appear after the -Djava.security.manager flag. If it is known in advance that the user prefers using the default global security manager installed from the command line, invoking the setSecurityManager() method in code can be forgone and substituted with just the getSecurityManager() method as the security manager is installed using the command line flag and need not be aet explicitly. A custom security manager can be made the default and enforced globally by specifying its absolute path location immediately after an equal-to sign that appears after the flagin code. In fact, using this method will throw a SecurityException if the current security policy enforced by the global security manager does not permit replacements (by not granting the RuntimePermission("setSecurityManager")).

The default policy file java.policy grants a few permissions (reading system properties, binding to unprivileged ports and so forth) and can be found in the ~/java.home/lib/security directory on UNIX-like systems and its equivalent on Microsoft Windows systems. There is also a user specific policy file in the user's home directory. The union of both these policy files defines the permissions given to a program. Refer to the java.security file to set which policy files should be used. If either of these is deleted, by default no permissions are granted to the implementing code.

...

Wiki Markup
Notably, the policy file specified in the argument is ignored when the {{policy.allowSystemProperty}} property in the security properties file ({{java.security}}) is set to {{false}}. Its default value is {{true}}. The document "Default Policy Implementation and Policy File Syntax" \[[Policy 02|AA. Java References#Policy 02]\] discusses writing policy files in depth.  

Noncompliant Code Example

Even when the SecurityManager API is used, there can be instances where the appropriate checks are not installed. This noncompliant code example passes a null value to the setSecurityManager method that is responsible for setting the expected SecurityManager argument. As a result, no security manager is installed (assuming that the security manager is not installed from the command line).

Code Block
bgColor#FFcccc

try {
  System.setSecurityManager(null);
} catch (SecurityException se) { 
  // cannot set security manager, log to file
}

Compliant Solution

This compliant solution demonstrates how a custom SecurityManager class called CustomSecurityManager can be instantiated by invoking its constructor with a password and set as the default security manager. The APIs that have security checks built into them will use the custom security manager subsequently.

Code Block
bgColor#ccccff

try {
  System.setSecurityManager(new CustomSecurityManager("password here"));
} catch (SecurityException se) { 
  // cannot set security manager, log to file
}

Compliant Solution

An alternative is to use the default security manager instead of a custom one, as shown below. To do this, change the active instance to java.lang.SecurityManager (invoke setSecurityManager() with the argument new SecurityManager()).

Code Block
bgColor#ccccff

try {
  System.setSecurityManager(new SecurityManager());
} catch (SecurityException se) { 
  // cannot set security manager, log to file
}

Risk Assessment

Running Java code without a Security Manager being set means that there is no restrictive sandbox and arbitrary code may get executed.

...