Last updated by 5 years ago

Page: Discovering a web application's security requirements, Version:0

Author: Mark S. Petrovic, mspetrovic at gmail dot com Originally from: http://www.petrovic.org/content/SecMgrTutorial/sm.html

Introduction

The Java Runtime Environment provides well-documented means by which an application can run subject to a defined security policy. The purpose of this managed security is to selectively grant or deny the application access to specific system resources. For our purposes, resources are things such as system- and application-level properties, disk files, network connections, and class loading privileges, to name a few. Resources represent things the application either wants to know or do. It is the Java java.lang.SecurityManager class that enforces this resource access, with the rules of enforcement based on simple rules in a text-based human readable security policy file.

In this article we introduce and discuss a tool, a profiling security manager, that programmatically produces a starting point in crafting an effective security policy. This draft policy describes to what resources the application wants access and in what capacity (e.g., read, write). Our motivation is for both educational purposes and to develop a tool to learn what resources complex applications require access, and to what degree, to run according to their specification. The rules produced by the tool may be used as a point of departure in producing a policy file for these complex applications, presumably sufficiently complex that producing a fine-grained policy file without runtime information may be too difficult, or simply as a subject of study and examination.

The version of the profiling security manager discussed here requires a late-model Sun JVM, as it relies on reflection to acquire information on a particular system class's private member data. I used JSE 5, and the tool requires java.security.AccessControlContext.context of type ProtectionDomain[] to exist.

The default Security Manager

By default a Java application runs with no runtime security manager. The application has full access to the machine resources, including disk, network, and application shutdown. Such broad access is easily restricted, however. An application can be forced to run under a "default" Java security policy by setting the -Djava.security.manager option on the JVM command line.

Consider this simple application, designed to print the user's home directory represented by the System property user.home

public class PrintHome {
   public static void main(String[] argv) {
      System.out.println(System.getProperty("user.home"));
   }
}
and with this runtime invocation
$ java -Djava.security.manager PrintHome
Exception in thread "main" java.security.AccessControlException: access denied (java.util.PropertyPermission user.home read)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:264)
at java.security.AccessController.checkPermission(AccessController.java:427)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1285)
at java.lang.System.getProperty(System.java:627)
at PrintHome.main(PrintHome.java:5)
The application fails to execute because the default security manager running with the default security policy forbids accessing the property user.home. Without the ability to read property user.home, the application cannot fulfill its intended purpose. This privilege must be granted explicitly in a runtime policy file.

Creating a policy file policy.txt, containing the single rule

grant codeBase "file:/home/cid/Projects/CustomSecurityManager/" {permission java.util.PropertyPermission "user.home", "read";};
and rerunning the application with a reference to the policy file solves the problem of access to user.home:
$ java -Djava.security.policy=policy.txt -Djava.security.manager PrintHome
/home/u
The class PrintHome resides in the directory /home/cid/Projects/CustomSecurityManager/, and the rule permits any code originating in that directory to read system property user.home. As a result, the rule allows PrintHome to run as intended.

Introducing ProfilingSecurityManager

For simple applications, creating a policy file by hand is relatively straightforward and uninvolved. And even more so when one takes advantage of powerful URL specification rules allowed in the policy file. Using advanced rules notation, one can specify codebase URLs that refer recursively to entire directory trees. While such recursive URL specification is powerful, it can also mask to the human reader the true depth of the resource needs of the application. It is precisely that fine-grained depth that we seek.

We are interested in a programmatic method of determining precisely which resources to which an application requires access for it to successfully execute over its runtime trajectory. Toward that end, we introduce the custom security manager ProfilingSecurityManager. ProfilingSecurityManager extends java.lang.SecurityManager, but does not implement a security policy in the traditional sense. It instead determines what that security policy would be if the application were granted access to everything it requests at runtime -- under the application's intended conditions of use, of course.

To use ProfilingSecurityManager, specify it as the security manager when the application is invoked, noting that no policy file specification is necessary

$ java -classpath .:classes -Djava.security.manager=com.homosuperiorus.security.ProfilingSecurityManager PrintHome

The custom security manager will write to System.out the rules needed in a policy file that will allow the application to run without throwing security violation exceptions:

grant codeBase "file:/home/cid/Projects/CustomSecurityManager/" {permission java.util.PropertyPermission "user.home", "read";};

Because the raw output from ProfilingSecurityManager can legitimately contain duplicate grant statements, and in the order the running application requires them, a Perl script parsecodebase.pl is provided to aggregate, format, and output only unique rules, grouped by codebase. Rules must be processed after runtime, because only then is it known that the ProfilingSecurityManager is finished outputting new rules.

Rerunning the application with output processed by parsecodebase.pl

$ java -classpath .:classes -Djava.security.manager=com.homosuperiorus.security.ProfilingSecurityManager PrintHome  | parsecodebase.pl
grant codeBase "file:/home/cid/Projects/CustomSecurityManager/" {permission java.util.PropertyPermission "user.home", "read";};