The static method java.security.AccessController
class is part of Java's security mechanism; it is responsible for enforcing the applicable security policy. This class's static doPrivileged()
method executes a code block with a relaxed security policy. The doPrivileged()
method stops permissions from being checked further down the call chain.
Consequently, any method that invokes doPrivileged()
must assume 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 SEC03-J. Do not allow tainted variables in doPrivileged blockssecurity on the code block supplied to doPrivileged()
. Likewise, code in the doPrivileged()
method must not leak sensitive information or capabilities.
For example, suppose that a web application must maintain a sensitive password file for a web service and also must run untrusted code. The application could then enforce a security policy preventing the majority of its own code—as well as all untrusted code—from accessing the sensitive file. Because it must also provide mechanisms for adding and changing passwords, it can call the doPrivileged()
method to temporarily allow untrusted code to access the sensitive file. In this case, any privileged block must prevent all information about passwords from being accessible to untrusted code.
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 Because the method is public, it could be invoked by an untrusted caller.
Code Block | ||
---|---|---|
| ||
public class PasswordPasswordManager { public static void changePassword() throws FileNotFoundException { FileInputStream fin = openPasswordFile(password_file); // testTest old password with password in file contents; change password, // then close the password file } public static FileInputStream openPasswordFile() throws FileNotFoundException { final String password_file = "password"; FileInputStream fin = //null; Declare as final andtry assign{ before the body of the anonymousfin inner class = AccessController.doPrivileged( // Array f[] isnew used to maintain language semantics while using final PrivilegedExceptionAction<FileInputStream>() { finalpublic FileInputStream f[] =run() throws FileNotFoundException {null}; // Sensitive Use own privilege to open the sensitive password file action; can't be done outside privileged block AccessController.doPrivileged(new PrivilegedAction() { FileInputStream in public= Objectnew runFileInputStream(password_file) {; try { return in; f[0] = new FileInputStream(password_file); // Perform privileged action } }); } catch (FileNotFoundExceptionPrivilegedActionException cnfx) { Exception cause = x.getException(); // cannot recover if password(cause fileinstanceof isFileNotFoundException) not{ found; log to sensitive file throw (FileNotFoundException) cause; } } else { return null; //throw Still mandatory to return from run()new Error("Unexpected exception type", cause); } }); return f[0]; // Returns a reference to privileged objects (inappropriate) fin; } } |
Compliant Solution
...
In general, when any method containing the doPrivileged()
a privileged block exposes a field (such as a an object 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 untrusted caller can call changePassword()
but cannot directly access the open password fileinvoke the openPasswordFile()
method.
Code Block | ||
---|---|---|
| ||
public class PasswordPasswordManager { public static void changePassword() throws FileNotFoundException { // ... } private static FileInputStream openPasswordFile() throws FileNotFoundException { // ... } } |
Compliant Solution (
...
Hiding Exceptions)
The previous noncompliant code example and the previous compliant solution logs the exception instead of letting a FileNotFoundException
propagate to a caller, in compliance with rule EXC06-J. Do not allow exceptions to transmit 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 failurethrow a FileNotFoundException
when the password file is missing. If the existence of the password file is itself considered sensitive information, this exception also must be prevented from leaking outside the trusted code.
This compliant solution suppresses the exception, leaving the array to contain a single null value to indicate that the file does not exist. It uses the simpler PrivilegedAction
class rather than PrivilegedExceptionAction
to prevent exceptions from propagating out of the doPrivileged()
block. The Void
return type is recommended for privileged actions that do not return any value.
Code Block | ||
---|---|---|
| ||
class PasswordManager { public static void readFont() throws FileNotFoundException { changePassword() { FileInputStream fin = openPasswordFile(); if (fin == null) { // Use own privilege to open the font file No password file; handle error } // Test old password with password in file contents; change password } private static FileInputStream openPasswordFile() { final String fontpassword_file = "fontfilepassword"; try { final FileInputStream fin[] final= InputStream{ innull =}; AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>PrivilegedAction<Void>() { public InputStreamVoid run() throws FileNotFoundException { try { return openFontFile(font_file); // Sensitive call the privileged method here action; can't be done outside // doPrivileged() } }block fin[0] = new FileInputStream(password_file); // Perform other operations } catch (PrivilegedActionExceptionFileNotFoundException excx) { Exception cause = exc.getException(); if (cause// instanceofReport FileNotFoundException)to {handler throw (FileNotFoundException)cause; } } elsereturn {null; throw new Error("Unexpected exception type", cause); } }); return }fin[0]; } } |
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 and can leak capabilities. 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 Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SEC02SEC00-J | medium Medium | likely Likely | high 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 Assuming user-provided tagging of sensitive information, we could do some kind of escape analysis could be performed on the doPrivileged()
blocks and perhaps to prove that nothing sensitive leaks out of from them. We could even use something akin to thread coloring Methods similar to those used in thread-role analysis could be used 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
...
...
Bibliography
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="22898173-c05f-4675-b2fc-4d8b679c8051"><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="a6b477af-427c-4382-b3c6-db57359ceed0"><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> |
Guideline 9-3 / ACCESS-3: Safely invoke |
Android Implementation Details
The java.security
package exists on Android for compatibility purposes only, and it should not be used.
Bibliography
[API 2014] | |
Section 6.4, " |
...
14. Platform Security (SEC) 14. Platform Security (SEC) SEC03-J. Do not allow tainted variables in doPrivileged blocks