...
This noncompliant code example instantiates a Hashtable
and defines a removeEntry()
method to allow the removal of its entries. This method is considered sensitive, perhaps because the hash table contains sensitive information. However, the method is public and nonfinal, which leaves it exposed to malicious callers.
Code Block | ||
---|---|---|
| ||
class SensitiveHash {
Hashtable<Integer,String> ht = new Hashtable<Integer,String>();
public void removeEntry(Object key) {
ht.remove(key);
}
}
|
...
This compliant solution installs a security check to protect entries from being maliciously removed from the Hashtable
instance. A SecurityException
is thrown if the caller lacks the java.security.SecurityPermission
removeKeyPermission
.
Code Block | ||
---|---|---|
| ||
class SensitiveHash {
Hashtable<Integer,String> ht = new Hashtable<Integer,String>();
void removeEntry(Object key) {
check("removeKeyPermission");
ht.remove(key);
}
private void check(String directive) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkSecurityAccess(directive);
}
}
}
|
...
This noncompliant code example uses the SecurityManager.checkRead()
method to check whether the file schema.dtd
can be read from the file system. The check*()
methods lack support for fine-grained access control. For example, the check*()
methods are inadequate to enforce a policy permitting read access to all files with the dtd
extension and forbidding read access to all other files. Code that is not itself part of the JDK must not override the check*()
methods because the default implementations of the Java libraries already use these methods to protect sensitive operations.
Code Block | ||
---|---|---|
| ||
SecurityManager sm = System.getSecurityManager();
if (sm != null) { // check whether file may be read
sm.checkRead("/local/schema.dtd");
}
|
...
This compliant solution shows the single argument checkPermission()
method that checks to see whether the files in the local
directory that have the dtd
extension can be read. DTDPermission
is a custom permission that enforces this level of access. Even if the java.io.FilePermission
is granted to the application with the action read
, DTD
files are subject to additional access control.
Code Block | ||
---|---|---|
| ||
SecurityManager sm = System.getSecurityManager();
if (sm != null) { //check whether file can be read or not
DTDPermission perm = new DTDPermission("/local/", "readDTD");
sm.checkPermission(perm);
}
|
...
A cleaner approach to making a security check from a different context is to take a snapshot of the execution context in which the check must be performed, using the java.security.AccessController.getContext()
method that returns an AccessControlContext
object. The AccessControlContext
class itself defines a checkPermission()
method that encapsulates a context instead of accepting the current executing context as an argument. This allows the check to be performed at a later time, as shown in the following example.
Code Block | ||
---|---|---|
| ||
// Take the snapshot of the required context, store in acc and pass it to another context
AccessControlContext acc = AccessController.getContext();
// Accept acc in another context and invoke checkPermission() on it
acc.checkPermission(perm);
|
...
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SEC04-J | high | probable | medium | P12 | L1 |
Automated Detection
Identifying sensitive operations requires assistance from the programmer; fully automated identification of sensitive operations is beyond the current state of the art.
Given knowledge of which operations are sensitive, as well as which specific security checks must be enforced for each operation, an automated tool could reasonably enforce the invariant that the sensitive operations are invoked only from contexts where the required security checks have been performed.
Android Implementation Details
The java.security
package exists on Android for compatibility purposes only and it should not be used.
Bibliography
[API 2006] |