You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 76 Next »

In Java SE 6 and Java SE 7, privileged code either uses the AccessController mechanism or must be signed by an owner (or provider) who is trusted by the user. Attackers could link privileged code with malicious code if the privileged code directly or indirectly invokes code from another package. Trusted jar files often contain code that lacks direct privileges, but that depends on privileged code; such code is known as security-sensitive code. If an attacker can link security-sensitive code with malicious code, they can indirectly cause incorrect behavior with sensitive data. This is called a mix and match attack.

Execution of untrusted code causes loss of privileges. When trusted code calls untrusted code that attempts to perform some action requiring permissions withheld by the security policy, the action is not allowed. However, privileged code may use a class that exists in an untrusted container and performs only unprivileged operations. If the attacker were to replace this class with a malicious implementation, the trusted code would retrieve incorrect results.

According to the Java API [[JarSpec 2008]], JAR file specification

A package sealed within a JAR specifies that all classes defined in that package must originate from the same JAR. Otherwise, a SecurityException is thrown.

Sealing a JAR file automatically enforces the requirement of keeping privileged code together. In addition, it is important to adhere to rule OBJ02-J. Minimize the accessibility of classes and their members.

Noncompliant Code Example (Privileged Code)

This noncompliant code example uses a doPrivileged block and calls a method defined in a class in a different, untrusted jar file.

package trusted;
import untrusted.RetValue;

public class MixMatch {
  private void privilegedMethod() throws IOException {
    try {
      AccessController.doPrivileged(
        new PrivilegedExceptionAction<FileInputStream>() {
          public FileInputStream run() throws FileNotFoundException {
            final FileInputStream fis = new FileInputStream("file.txt");
            try {
              RetValue rt = new RetValue();

              if (rt.getValue() == 1) {
                // do something with sensitive file
              }
            } finally {
              fis.close();
            }
          }
        }
      );
    } catch (PrivilegedActionException e) {
      // forward to handler and log
    }

  }

  public static void main(String[] args) throws IOException {
    MixMatch mm = new MixMatch();
    mm.privilegedMethod();
  }
}


// In another jar file:
package untrusted;

class RetValue {
  public int getValue() {
    return 1;
  }
}

An attacker can provide an implementation of class RetValue so that the privileged code uses an incorrect return value. Even though class MixMatch consists only of trusted, signed code, an attacker can still cause this behavior by maliciously deploying a legally signed jar file containing the untrusted RetValue class.

This example comes close to violating SEC01-J. Do not allow tainted variables in privileged blocks, but does not do so. It instead allows potentially tainted code in its doPrivileged() block, which is a similar issue.

Noncompliant Code Example (security-sensitive code)

This noncompliant code example improves upon the previous example by moving the use of the RetValue class outside the doPrivileged() block.

package trusted;
import untrusted.RetValue;

public class MixMatch {
  private void privilegedMethod() throws IOException {
    try {
      final FileInputStream fis = AccessController.doPrivileged(
        new PrivilegedExceptionAction<FileInputStream>() {
          public FileInputStream run() throws FileNotFoundException {
            return new FileInputStream("file.txt");
          }
        }
      );
      try {
        RetValue rt = new RetValue();

        if (rt.getValue() == 1) {
          // do something with sensitive file
        }
      } finally {
        fis.close();
      }
    } catch (PrivilegedActionException e) {
      // forward to handler and log
    }
  }

  public static void main(String[] args) throws IOException {
    MixMatch mm = new MixMatch();
    mm.privilegedMethod();
  }
}


// In another jar file:
package untrusted;

class RetValue {
  public int getValue() {
    return 1;
  }
}

Although the RetValue class is used only outside the doPrivileged() block, the behavior of RetValue.getValue() certainly affects the behavior of security-sensitive code; that is, the code that operates on the file opened within the doPrivileged() block. Consequently, an attacker can still exploit the security-sensitive code with a malicious implementation of RetValue.

Compliant Solution

This compliant solution combines all security-sensitive code into the same package and the same jar file. It also reduces the accessibility of the getValue() method to package-private. Sealing the package is necessary to prevent attackers from inserting any rogue classes.

package trusted;

public class MixMatch {
  // ...
}


// In the same signed & sealed jar file:
package trusted;

class RetValue {
  int getValue() {
    return 1;
  }
}

To seal a package, use the sealed attribute in the jar file's manifest file header, as follows.

Name: trusted/ // package name
Sealed: true  // sealed attribute

Exception

ENV01-EX0: Independent groups of privileged code and associated security-sensitive code (a "group" hereafter) may be placed in separate sealed packages and even in separate jar files, subject to certain enabling conditions. These conditions are:

  • The code in any one of these independent groups must lack any dynamic or static dependency on any of the code in any of the other groups. This means that code from one such group cannot cannot invoke code from any of the others, whether directly or transitively.
  • All code from any single group is contained within one or more sealed packages.
  • All code from any single group is contained within a single signed jar file.

Risk Assessment

Failure to place all privileged code together in one package and seal the package can lead to mix and match attacks.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ENV01-J

high

probable

medium

P12

L1

Automated Detection

Detecting code that should be considered privileged or sensitive requires programmer assistance. Given identified privileged code as a starting point, automated tools could compute the closure of all code that can be invoked from that point. Such a tool could plausibly determine whether all code in that closure exists within a single package. A further check of whether the package is sealed appears feasible.

Related Guidelines

MITRE CWE

CWE ID 349, "Acceptance of Extraneous Untrusted Data With Trusted Data"

Bibliography

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="71d2b65c-2284-4a69-8ed9-ebc7cc89a6e7"><ac:plain-text-body><![CDATA[

[[API 2006

AA. Bibliography#API 06]]

 

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="5e14dfe8-37b8-4c52-81ba-7aa195d631a0"><ac:plain-text-body><![CDATA[

[[McGraw 1999

AA. Bibliography#Ware 99]]

Rule 7: If You Must Sign Your Code, Put It All in One Archive File (sic)

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="7ce162ae-f46c-4e7c-b01e-64a55ef69ed1"><ac:plain-text-body><![CDATA[

[[Ware 2008

AA. Bibliography#Ware 08]]

 

]]></ac:plain-text-body></ac:structured-macro>


      15. Runtime Environment (ENV)      ENV02-J. Use system properties rather than environment variables when possible

  • No labels