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 privilegesSometimes code needs to take into account the privileges of another context while performing a security critical action. Granting such code all of the privileges of the current execution context (snapshot of the current thread) can expose a vulnerability. Ideally, code should only be granted the privileges it needs to complete its operation, with no excess privileges allowed. This adds extra complexity to privileged code, and often the cost (in terms of complexity and maintainability) for carefully restricting privileges must be weighed against the additional security granted, when deciding how much restriction of privileges is necessary.
Noncompliant Code Example
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), reading a file) using the wrapper method performActionOnFile().:
| Code Block | ||
|---|---|---|
| ||
private FileInputStream 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;
}
});
return f[0];
}
// wrapperWrapper method
public void performActionOnFile() {
try (FileInputStream f = openFile();)){
// Perform operation
} catch (Throwable t) {
// Handle exception
}
}
|
The security policy that applies to this code may grant the permissions to both read and write to the file. However, the caller only requires read access to the fileIn 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 violates the principle of least privilege by also providing the caller code block with superfluous write accessprivileges.
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 read permission -reading permissions can be created as an inner class. :
| Code Block | ||
|---|---|---|
| ||
private FileInputStream 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
context);
return f[0];
}
private static class FileAccessControlContext {
public 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)});
}
}
// Wrapper method
public void performActionOnFile() {
try openFile(FileAccessControlContext.INSTANCE);(final FileInputStream f =
// Grant only grant open-for-reading perms, see below
}
privileges
openFile(FileAccessControlContext.INSTANCE)) {
// Perform action
} catch (Throwable t) {
// Handle exception
}
}
|
Callers that lack permission to create an appropriate AccessControlContext can request one Alternatively, an appropriate AccessControlContext 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 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 does not need to be declared private, provided permissions are restricted by accepting a context argument. to create the instance.
Applicability
Failure to follow the principle of least privilege can lead to abuse of the excess privileges that were granted.
Related Guidelines
...
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
| [API |
...
...