According to the Class SecurityManager
documentation [[API 06]]:
The security manager is a class that allows applications to implement a security policy. It allows an application to determine, before performing a possibly unsafe or sensitive operation, what the operation is and whether it is being attempted in a security context that allows the operation to be performed. The application can allow or disallow the operation.
As an example, the security manager denies applets all but the most essential privileges. It is designed to protect inadvertent system modification, information leakage and user impersonation. For Java applications that run from the command line, a default or custom security manager can be set using a special flag described a little later. Alternatively, it is possible to install a security manager programatically.
From Java 2 SE Platform onwards, SecurityManager
is a non-abstract class. As a result, there is no explicit requirement of overriding its methods. To create and use a security manager programatically, the code must have the runtime permissions createSecurityManager
(to instantiate SecurityManager
) and setSecurityManager
to install it.
The security manager is closely related to the AccessController
. The former is used as a hub for access control whereas the latter is the implementer of a particular access control algorithm. Two requirements necessitate the use of the security manager:
- Providing backward compatibility: Legacy code often contains custom implementations of the security manager class because it was originally
abstract
.
- Defining custom policies: It is sometimes desired to subclass the security manager to define multilevel, coarse or fine grained security policies with system wide application.
The Java Security Architecture Specification [[SecuritySpec 08]] aptly paints the picture:
We encourage the use of
AccessController
in application code, while customization of a security manager (via subclassing) should be the last resort and should be done with extreme care. Moreover, a customized security manager, such as one that always checks the time of the day before invoking standard security checks, could and should utilize the algorithm provided byAccessController
whenever appropriate.
Noncompliant Code Example
The worst form of non-compliance is not using the the security manager at all. Even when used, there can be cases where the appropriate checks are not installed. In the noncompliant code example that follows, a null
value is passed to the setSecurityManager
method that is responsible for establishing a current 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).
try { System.setSecurityManager(null); } catch (SecurityException se) { System.out.println("SecurityManager is already set!"); }
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.
try { System.setSecurityManager(new CustomSecurityManager("password here")); } catch (SecurityException se) { System.out.println("SecurityManager is already set!"); }
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.
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) { System.out.println("Not allowed"); }
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()
).
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) { System.out.println("Not allowed"); }
Compliant Solution
The methods detailed in the preceding compliant solutions were more prevalent in JDK versions 1.x. 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
class.
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
method.
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 here, passing in the instance of an AccessControlContext
as the context
argument. 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 currently execution context and as a result does not supersede the security manager's two argument version. There is also, however, another (cleaner and preferable) way to handle the security check from a different context.
This is accomplished by taking a snapshot of the currently executing 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 taking in the currently executing context. This is shown below.
// Take the snapshot of the required context AccessControlContext acc = AccessController.getContext(); // ... acc.checkPermission(perm); // Check permissions in another context
Compliant Solution
Any Java program (bean, servlet or application) can instantiate a SecurityManager
. However, for 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 the user operates using a custom security policy and does not want to rely on the vendor supplied security policy. The default security manager at the user end can be installed using the flags as follows:
java -Djava.security.manager -Djava.security.policy=policyURL LocalJavaApp
If it is known in advance that the user prefers using a custom security policy, 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 set explicitly. A custom security manager can be installed by adding the absolute path to the custom security manager, after an equal-to sign appended immediately after the flag.
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.
If the default policy file needs to be bypassed in lieu of a custom policy file, a double equals (==
) idiom should be used.
java -Djava.security.manager -Djava.security.policy==policyURL LocalJavaApp
The appletviewer
automatically installs a security manager with the standard policy file. To specify additional policy files, use the -J
flag.
appletviewer -J-Djava.security.manager -Djava.security.policy==policyURL LocalJavaApp
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]] discusses writing policy files in depth.
Risk Assessment
Running Java code without a Security Manager being set means that there is no restrictive sandbox and arbitrary code may get executed.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
ENV30- J |
high |
probable |
low |
P18 |
L1 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[API 06]] Class SecurityManager, Class AccessControlContext, Class AccessController
[[Policy 02]]
[[Pistoia 04]] Section 7.4, The Security Manager
[[Gong 03]] Section 6.1, Security Manager
[[SecuritySpec 08]] 6.2 SecurityManager versus AccessController
[[MITRE 09]] CWE ID 358 "Improperly Implemented Security Check for Standard"
ENV03-J. Limit remote uses of JVM Monitoring and Managing 01. Runtime Environment (ENV) ENV31-J. Never grant AllPermission to untrusted code