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]\]: |
\[1\] We want to grant each applet or application the minimum privileges it needs.
\[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.
\[3\] We want a class's privileges to be "turned off" except for brief periods of time.
\[4\] We even want to reduce the privileges of some of the built-in system classes.
\[Our numbering.\] |
The ways in which these goals can be achieved are discussed below.
JAR file). 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.AccessController mechanism. 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 a doPrivileged block. The AccessController mechanism 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 the doPrivileged blocks must be kept to a minimum to avoid security vulnerabilities.accessClassInPackage permission 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.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.
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");
} catch (FileNotFoundException cnf) {
// 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.
This compliant solution removes the call to {{System.loadLibrary()}}. Any operations on the file descriptor {{f\[0\]}} must also occur outside the privileged block to make it easier to audit privileged code. |
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 ...
}
|
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. |
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().
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 access.
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 of the current execution context's domains and those of the context passed as the second argument. Consequently, a caller that requires only read permission to the file can pass a context that has only the file read permission.
private void 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 acc) {
openFile(acc); // Caller's AccessControlContext
}
|
An AccessControlContext that grants the file read permission can be created as an inner class:
private static class FileAccessControlContext {
private 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. In the special case where all the callers are known (for example, when all are private methods of a private class), the single argument method AccessController.checkPermission(permission) offers improved simplicity and performance. The two argument form should be used for all cases where there may be unknown callers. The performActionOnFile() method need not be declared private provided permissions are restricted by accepting a context argument.
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 |
TODO
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
\[[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] |
02. Platform Security (SEC) 02. Platform Security (SEC) SEC01-J. Minimize the accessibility of classes and their members