The 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 doPrivileged
is used to affirm that the invoking method is taking responsibility for enforcing its own privileges and that the access permissions of its callers should be ignored. For example, an application may have permissions to operate on a sensitive file, however, a caller of this application may be allowed to operate with only basic user permissions. Invoking doPrivileged()
in the context of this method allows the application operating with only basic user permissions to operate on the sensitive file.security 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
reference to its caller. This allows an untrusted caller to call openPasswordFile()
directly and obtain a reference to for the sensitive password file because of the inherent privileges possessed by the corresponding code. Because the method is public, it could be invoked by an untrusted caller.
Code Block | ||
---|---|---|
| ||
public class PasswordPasswordManager { public static void changePassword(final String password_file) throws FileNotFoundException { FileInputStream fin; fin = openPasswordFile(password_file); } public static FileInputStream openPasswordFile(String password_file) throws FileNotFoundException { // Test old password with password in file contents; change password, // Declarethen asclose finalthe andpassword assignfile before the} body ofpublic thestatic anonymous inner classFileInputStream openPasswordFile() // Array f[]throws isFileNotFoundException used{ to maintain language semanticsfinal whileString usingpassword_file final= "password"; finalFileInputStream FileInputStreamfin f[]={ null}; //try Use{ own privilege to open the sensitivefin password file = AccessController.doPrivileged( AccessController.doPrivileged( new PrivilegedActionPrivilegedExceptionAction<FileInputStream>() { public ObjectFileInputStream run() throws FileNotFoundException { // Sensitive try { action; can't be done outside privileged block f[0]FileInputStream in = new FileInputStream("c:\\" + passowrdpassword_file); //Perform privileged action return in; } }); } catch (FileNotFoundExceptionPrivilegedActionException cnfx) { System.err.println(cnf.getMessage()); } Exception cause = x.getException(); if (cause instanceof return null;FileNotFoundException) { //Still mandatory to return fromthrow run(FileNotFoundException) cause; } else { throw new Error("Unexpected exception type", }cause); return f[0]; //Returns a reference to privileged objects (inappropriate) } } } return 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.
Compliant Solution
The This compliant solution mitigates the vulnerability by declaring openPasswordFile()
method controls access to the sensitive password file and returns its reference. For this reason, it should not be directly invokable. Instead, the changePassword()
method must be used to forward any requests to openPasswordFile()
. This is because changePassword()
does not return a reference to the sensitive file to any caller and processes the file internally. Observe that caller supplied (tainted) inputs are not used because the name of the password file is hard-coded. be private. Consequently, an untrusted caller can call changePassword()
but cannot directly invoke the openPasswordFile()
method.
Code Block | ||
---|---|---|
| ||
public class PasswordPasswordManager { privatepublic static void changePassword() throws FileNotFoundException { // Use... own privilege} to openprivate thestatic sensitiveFileInputStream passwordopenPasswordFile() file final Stringthrows password_file = "password"; FileNotFoundException { // ... } } |
Compliant Solution (Hiding Exceptions)
The previous noncompliant code example and the previous compliant solution throw 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 changePasswordfinal FileInputStream f[] = {null}; AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { f[0]FileInputStream fin = openPasswordFile(password_file); // call the privileged method here if (fin }catch(FileNotFoundException cnf== null) { // No password System.err.println("Error: Operation could not be performed");file; handle error } // Test old password returnwith null; password in } }); //Perform other operations such as password verificationfile contents; change password } private static FileInputStream openPasswordFile(String password_file) throws FileNotFoundException { FileInputStream ffinal String password_file = new FileInputStream("c:\\" + password_file)"password"; //final Perform read/write operations on password fileFileInputStream fin[] = { null }; return f; } } |
The previous compliant solution prints a general error instead of revealing sensitive information (See EXC01-J. Do not allow exceptions to transmit sensitive information) and as a result, swallows all exceptions. Sometimes no sensitive information can be revealed by any of the possible exceptions. In such cases, an equivalent mechanism that allows exceptions to be wrapped can be used. This allows the caller to obtain better diagnostic information. For example, if an applet doesn't have access to read system files that contain fonts, it can accomplish the task from a privileged block without revealing any sensitive information. In fact, by not swallowing exceptions, the client can deduce the symptoms of a read failure quite easily.
Code Block | ||
---|---|---|
| ||
public static void readFont() throws FileNotFoundExceptionAccessController.doPrivileged(new PrivilegedAction<Void>() { // Use own privilege to openpublic theVoid fontrun() file{ final String font_file = "fontfile"; try { final InputStream in = AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>() { public InputStream run() throws FileNotFoundException { // Sensitive action; can't be done outside return// openFontFiledoPrivileged(font_file); //call the privileged method here ) block } fin[0] }= new FileInputStream(password_file); // Perform other operations } catch (PrivilegedActionExceptionFileNotFoundException excx) { Exception cause = exc.getException(); // Report to handler if (cause instanceof FileNotFoundException) {} throw (FileNotFoundException)causereturn null; } else { throw} new Error("Unexpected exception type",cause}); } return } fin[0]; } } |
In summary, if the code can throw a checked exception without leaking sensitive information, prefer 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 ad 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.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SEC36SEC00-J | medium Medium | likely Likely | high High | P6 | L2 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Wiki Markup |
---|
\[[API 06|AA. Java References#API 06]\] [method doPrivileged()|http://java.sun.com/javase/6/docs/api/java/security/AccessController.html#doPrivileged(java.security.PrivilegedAction)]
\[[Gong 03|AA. Java References#Gong 03]\] Sections 6.4, AccessController and 9.5 Privileged Code
\[[SCG 07|AA. Java References#SCG 07]\] Guideline 6-1 Safely invoke java.security.AccessController.doPrivileged
\[[MITRE 09|AA. Java References#MITRE 09]\] [CWE ID 266|http://cwe.mitre.org/data/definitions/266.html] "Incorrect Privilege Assignment", [CWE ID 272|http://cwe.mitre.org/data/definitions/272.html] "Least Privilege Violation" |
Identifying sensitive information requires assistance from the programmer; fully automated identification of sensitive information is beyond the current state of the art.
Assuming user-provided tagging of sensitive information, escape analysis could be performed on the doPrivileged()
blocks to prove that nothing sensitive leaks out from them. Methods similar to those used in thread-role analysis could be used to identify the methods that must, or must not, be called from doPrivileged()
blocks.
Related Guidelines
CWE-266, Incorrect Privilege Assignment | |
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, " |
...
00. Security (SEC) 00. Security (SEC) SEC02-J. Do not expose standard APIs that may bypass Security Manager checks to untrusted code