A Java security policy grants permissions to code to allow access to specific system resources. A code source (an object of type CodeSource), to which a permission is granted, consists of the code location (URL) and a reference to the certificate(s) containing the public key(s) corresponding to the private key(s) used to digitally sign the code. Reference to the certificate(s) is pertinent only if the code was digitally signed. A protection domain encompasses a CodeSource and the permissions granted to code from that CodeSource, as determined by the security policy currently in effect. Consequently, classes signed by the same key and originating from the same URL are placed in the same protection domain. A class belongs to one and only one protection domain. Classes that have the same permissions but are from different code sources belong to different domains.
Each Java class runs in its appropriate domain, as determined by its code source. For any code running under a security manager to perform a secured action such as reading or writing a file, the code must be granted permission to perform that particular action. Privileged code can access privileged resources on behalf of an unprivileged caller by using the AccessController.doPrivileged() method. This is necessary, for example, when a system utility needs to open a font file on behalf of the user to display a document, but the application lacks permission to do so. To perform this action, the system utility uses its full privileges for obtaining the fonts, ignoring the privileges of the caller. Privileged code runs with all the privileges of the protection domain associated with the code source. These privileges often exceed those required to perform the privileged operation. Ideally, code should be granted only the minimum set of privileges required to complete its operation.
SEC53-J. Define custom security permissions for fine-grained security describes another approach to eliminating excess privileges.
Noncompliant Code Example
This noncompliant code example shows a library method that allows callers to perform a privileged operation (reading a file) using the wrapper method performActionOnFile():
| Code Block | ||
|---|---|---|
| ||
private FileInputStream openFile |
| Wiki Markup |
|---|
According to the principle of least privilege, code should not be granted more privileges than those required for performing the particular task. This means that sections of code that require elevated privileges should be kept to a minimum. McGraw and Felten enlist various goals of the principle of least privilege in the context of the Java programming language \[[McGraw 2000|AA. Bibliography#McGraw 00]\]: |
Wiki Markup \[1\] We want to grant each applet or application the minimum privileges it needs.
Wiki Markup \[2\] Rather than assigning a given applet's \[or application's\] entire collection of privileges to all of its classes, we want each class to get just what it needs.
Wiki Markup \[3\] We want a class's privileges to be "turned off" except for brief periods of time.
Wiki Markup \[4\] We even want to reduce the privileges of some of the built-in system classes.
| Wiki Markup |
|---|
\[Our numbering.\] |
The ways in which these goals can be achieved are discussed below.
- Applets rarely require elevated privileges. Sign only those applets that require elevated privileges; other applets should not be signed. (See guideline ENV00-J. Do not sign code that performs only unprivileged operations.) For applications, the security policy that defines the set of permissions should be as restrictive as possible. The default security policy file grants permissions sparingly, however, the flexible security model allows the user to grant additional permissions to applications by defining a custom security policy. Several guidelines deal with granting or limiting permissions:
- ENV00-J. Do not sign code that performs only unprivileged operations
- ENV03-J. Never grant AllPermission to untrusted code
- ENV04-J. Do not grant ReflectPermission with target suppressAccessChecks
- ENV05-J. Do not grant RuntimePermission with target createClassLoader
- There are several ways of satisfying the second goal of privilege separation to enhance security. Applets or applications that need to be signed can coexist with unsigned classes in the same package (or
JARfile). It is recommended that all privileged code be packaged together. (See guideline ENV01-J. Place all privileged code in a single package and seal the package for more information.) Furthermore, it is possible to grant privileges to code on the basis of the code base and/or its signer using a security policy.
- The third goal can be realized using the
AccessControllermechanism. This mechanism allows only certain parts of code to acquire elevated privileges. When a class needs to assert its privileges, it executes the privileged code in adoPrivilegedblock. TheAccessControllermechanism works in conjunction with the security policy in effect. Because users may be unaware of the details of the security model and incapable of correctly configuring security policies tailored to their requirements, privileged code present within thedoPrivilegedblocks must be kept to a minimum to avoid security vulnerabilities.
- The fourth goal can be achieved using a security manager to control the functions the trusted Java API can perform. (See guideline ENV02-J. Create a secure sandbox using a Security Manager.) When untrusted code should be disallowed from accessing system classes, it should be granted specific permissions to prevent it from accessing trusted classes in the specified packages. The
accessClassInPackagepermission provides the required functionality. (See guideline SEC12-J. Do not grant untrusted code access to classes existing in forbidden packages.) Doing so does not limit what system classes can do; however, it restricts the range of system packages that can be used from less-privileged code.
Noncompliant Code Example (Superfluous Code in doPrivileged Block)
This noncompliant code example shows an changePassword() method that attempts to open a password file using a doPrivileged block. The doPrivileged block also contains logic that operates on the file and a superfluous System.loadLibrary() call.
| Code Block | ||
|---|---|---|
| ||
public void changePassword() { final FileInputStream f[] = { null }; AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { String passwordFile = System.getProperty("user.dir") + File.separator + "PasswordFileName"; f[0] = new FileInputStream(passwordFile); // Operations on the file ... System.loadLibrary("LibName");"file"); } catch (FileNotFoundException cnffnf) { // Forward to handler } return null; } }); } |
This is a violation of the principle of least privilege because a caller who does not have the required privileges can indirectly load the library provided the security policy allows doing so. This transfers the burden of ensuring security to the administrator who implements the security policy.
Compliant Solution
...
|
...
return f[0];
}
// Wrapper method
public void performActionOnFile() {
try (FileInputStream f = openFile()){
// Perform operation
} catch (Throwable t) {
// Handle exception
}
}
|
In this example, the trusted code grants privileges beyond those required to read a file, even though read access to the file was the only permission needed by the doPrivileged() block. Consequently, this
| Code Block | ||
|---|---|---|
| ||
public void changePassword() {
final FileInputStream f[] = { null };
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
String passwordFile = System.getProperty("user.dir") + File.separator
+ "PasswordFileName";
f[0] = new FileInputStream(passwordFile);
} catch (FileNotFoundException cnf) {
// Forward to handler
}
return null;
}
});
// Operations on the file ...
}
|
| Wiki Markup |
|---|
Furthermore, {{f\[0\]}} should not leak out to untrusted code. (Refer to guideline [SEC02-J. Guard doPrivileged blocks against untrusted invocations}.) It is critical to keep the amount of code that requires elevated privileges to a minimum and audit privileged code carefully. |
Noncompliant Code Example
Sometimes code needs to take into account the privileges of another context while performing a security critical action. Granting such code the privileges of the current execution context (snapshot of the current thread) may expose a vulnerability.
This noncompliant code example shows a library method that allows callers to perform a privileged operation (such as a read or write to a file), using the wrapper method performActionOnFile().
| Code Block | ||
|---|---|---|
| ||
private void openFile() {
final FileInputStream f[] = {null};
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
f[0] = new FileInputStream("file");
} catch(FileNotFoundException fnf) {
// Forward to handler
}
return null;
}
});
}
// wrapper method
public void performActionOnFile() {
openFile();
}
|
The corresponding code is granted the permissions to both read and write to the file in the security policy. However, the caller only requires read access to the file. This code violates the principle of least privilege by also providing the caller with write accesscode block with superfluous privileges.
Compliant Solution
The two-argument form of doPrivileged() accepts an AccessControlContext object from the caller and restricts the privileges of the contained code to the intersection of the permissions privileges of the current execution context's domains protection domain and those of the context passed as the second argument. Consequently, a caller that requires only read permission to wishes to grant only permission to read the file can pass provide a context that has only the file read permission-reading permissions.
An AccessControlContext that grants the appropriate file-reading permissions can be created as an inner class:
| Code Block | ||
|---|---|---|
| ||
private voidFileInputStream openFile(AccessControlContext context) { if (context == null) { throw new SecurityException("Missing AccessControlContext"); } final FileInputStream f[] = { null }; AccessController.doPrivileged( new PrivilegedAction() { public Object run() { try { f[0] = new FileInputStream("file"); } catch (FileNotFoundException fnf) { // Forward to handler } return null; } }, context); // Restrict the privileges by passing the context argument } // Wrapper method public void performActionOnFile(AccessControlContext acccontext) {; openFile(acc); // Caller's AccessControlContext } |
An AccessControlContext that grants the file read permission can be created as an inner class:
| Code Block |
|---|
return f[0]; } private static class FileAccessControlContext { privatepublic static final AccessControlContext INSTANCE; static { Permission perm = new java.io.FilePermission("file", "read"); PermissionCollection perms = perm.newPermissionCollection(); perms.add(perm); INSTANCE = new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms)}); } } |
Alternatively, it can be obtained using AccessController.getContext() if the caller does not have privileges to create it.
In this example, the two-argument form is preferable because the openFile() method does not know whether the caller should be granted the read, write or both permissions. Prefer the single argument AccessController.checkPermission(permission) method when the permissions of the caller are known beforehand. The performActionOnFile() method need not be declared private provided permissions are restricted by accepting a context argument.
...
// Wrapper method
public void performActionOnFile() {
try (final FileInputStream f =
// Grant only open-for-reading privileges
openFile(FileAccessControlContext.INSTANCE)) {
// Perform action
} catch (Throwable t) {
// Handle exception
}
}
|
Callers that lack permission to create an appropriate AccessControlContext can request one using AccessController.getContext() to create the instance.
Applicability
Failure to follow the principle of least privilege can lead to privilege escalation.
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
SEC00-J | high | probable | high | P6 | L2 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
Bibliography
| Wiki Markup |
|---|
\[[API 2006|AA. Bibliography#API 06]\] Class {{java.security.AccessController}}
\[[McGraw 2000|AA. Bibliography#McGraw 00]\]
\[[MITRE 2009|AA. Bibliography#MITRE 09]\] CWE [272|http://cwe.mitre.org/data/definitions/272.html] |
result in untrusted, unprivileged code performing unintended privileged operations. However, carefully restricting privileges adds complexity. This added complexity and the associated reduction of maintainability must be traded off against any security improvement.
Bibliography
...
02. Platform Security (SEC) 02. Platform Security (SEC) SEC01-J. Minimize the accessibility of classes and their members