The static method java.security.AccessController.doPrivileged()
affirms that the invoking method assumes responsibility for enforcing its own privileges and that the access permissions of its callers should be ignored. For example, an application could have permissions to operate on a sensitive file, however, a caller of the application may be allowed to operate with only the basic permissions. Invoking doPrivileged()
in this context allows the application operating with basic permissions to use the sensitive file, for instance, when a user password change request requires an unprivileged application to use a more privileged application to set the new password.
This rule concerns sensitive information escaping from a doPrivileged()
block. For information about untrusted information entering a doPrivileged()
block, see SEC01-J. Do not allow tainted variables in doPrivileged blocks.
Noncompliant Code Example
In this noncompliant code example, the doPrivileged()
method is called from the openPasswordFile()
method. The openPasswordFile()
method is privileged and returns a FileInputStream
for the sensitive password file to its caller. Since the method is public, it could be invoked by an untrusted caller.
public class Password { public static void changePassword() throws FileNotFoundException { FileInputStream fin = openPasswordFile(password_file); // test old password with password in file contents; change password } public static FileInputStream openPasswordFile() { final String password_file = "password"; // Declare as final and assign before the body of the anonymous inner class // Array f[] is used to maintain language semantics while using final final FileInputStream f[] = {null}; // Use own privilege to open the sensitive password file AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { f[0] = new FileInputStream(password_file); // Perform privileged action } catch (FileNotFoundException cnf) { // cannot recover if password file is not found; log to sensitive file } return null; // Still mandatory to return from run() } }); return f[0]; // Returns a reference to privileged objects (inappropriate) } }
Compliant Solution (Logging Exceptions)
In general, when any method containing the doPrivileged()
block exposes a field (such as a reference) beyond its own boundary, it becomes trivial for untrusted callers to exploit the program.
This compliant solution mitigates the vulnerability by declaring openPasswordFile()
to be private. Consequently, an untrsuted caller can call changePassword()
but cannot directly access the open password file.
class Password { public static void changePassword() { // ... } private static FileInputStream openPasswordFile() { // ... } }
Compliant Solution (Throwing Wrapped Exceptions)
The previous compliant solution logs the exception instead of letting a FileNotFoundException
propagate to a caller, in compliance with rule ERR01-J. Do not allow exceptions to expose sensitive information.
But if none of the possible exceptions reveals sensitive information, we can use an equivalent mechanism that allows exceptions to be wrapped, consequently providing better diagnostic information for the caller. For example, an applet that lacks read-access to system files that contain fonts can accomplish the task from a privileged block without revealing any sensitive information. When non-sensitive exceptions provide more information, the client is better able to recognize the symptoms of a read failure.
public static void readFont() throws FileNotFoundException { // Use own privilege to open the font file final String font_file = "fontfile"; try { final InputStream in = AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>() { public InputStream run() throws FileNotFoundException { return openFontFile(font_file); // call the privileged method here } }); // Perform other operations } catch (PrivilegedActionException exc) { Exception cause = exc.getException(); if (cause instanceof FileNotFoundException) { throw (FileNotFoundException)cause; } else { throw new Error("Unexpected exception type", cause); } } }
In summary, if the code can throw a checked exception without leaking sensitive information, then use the form of doPrivileged()
method that takes a PrivilegedExceptionAction
instead of a PrivilegedAction
.
Risk Assessment
Returning references to sensitive resources from within a doPrivileged()
block can break encapsulation and confinement. Any caller who can invoke the privileged code directly and obtain a reference to a sensitive resource or field can maliciously modify its elements.
Guideline |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
SEC00-J |
medium |
likely |
high |
P6 |
L2 |
Automated Detection
Identifying sensitive information requires assistance from the programmer; fully-automated identification of sensitive information is beyond the current state of the art.
If we had user-provided tagging of sensitive information, we could do some kind of escape analysis on the doPrivileged()
blocks and perhaps prove that nothing sensitive leaks out of them. We could even use something akin to thread coloring to identify the methods that either must (or must not) be called from doPrivileged()
blocks.
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CWE ID 266, "Incorrect Privilege Assignment" |
|
|
CWE ID 272, "Least Privilege Violation" |
Guideline 6-2 Safely invoke java.security.AccessController.doPrivileged() |
Bibliography
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="05a7d742-c117-488e-9836-2f39eadce8da"><ac:plain-text-body><![CDATA[ |
[[API 2006 |
AA. Bibliography#API 06]] |
[method doPrivileged() |
http://java.sun.com/javase/6/docs/api/java/security/AccessController.html#doPrivileged(java.security.PrivilegedAction)] |
]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="70381b49-9a97-489d-acfd-a82e03befd0e"><ac:plain-text-body><![CDATA[ |
[[Gong 2003 |
AA. Bibliography#Gong 03]] |
Sections 6.4, AccessController and 9.5 Privileged Code |
]]></ac:plain-text-body></ac:structured-macro> |
14. Platform Security (SEC) 14. Platform Security (SEC) SEC01-J. Do not allow tainted variables in doPrivileged blocks