|
|
< Day Day Up > |
|
Java Security ModelA Java program runs within a JVM, and the JVM itself runs as a normal process on the host machine. As a user process, the JVM enjoys all the rights and privileges associated with the user on resources such as files, devices, ports, memory, CPU, disk space, keyboard, and so on as per the rules of the underlying OS (Operating System). The Java security model works within the confines of this boundary drawn by the OS. You may wonder梬hat is the need for an additional security model? Why isn't the OS security model adequate for Java programs? Let us ponder over these facts:
Hopefully, these points make a strong case for a Java platform security model, separate from and on top of the Operating System security. Java Language SecurityAs we noted earlier, Java is often claimed as a safe programming language. What does it mean? In simple terms, it means that the language has features that makes it much more difficult to write vulnerable code and it is much harder to subvert the language-defined security rules, either intentionally or unintentionally. This is accomplished by enforcing a number of rules: A code fragment can access code and data only as per the rules of the Java language. This includes enforcement of a number of rules: (a) A program can access only visible objects through valid references; (b) strict adherence to the access modifiers such as private, protected, public and so on; and (c) proper range checks on accessing array elements. Recall that attacks involving stack smashing and buffer overflow rely on passing control to code segments in violation of such rules in languages that do not enforce such rules. A variable must be initialized before use. Uninitialized variables are a source of many hard to detect bugs. They could also allow a program to access data stored by another program using the same memory locations. Java ensures that all memory objects are properly initialized and object references are checked for null values at runtime. The value of a final entity cannot be changed. Change of value for a final variable could alter the behavior of the program relying on this value and can introduce vulnerabilities. Type safety rules must be adhered to. Free casting of an object reference to another object reference would violate access rules of the language and could allow access of forbidden portions of the memory. Java runtime environment checks for such illegal casts at runtime and prevents them. This list is not exhaustive but gives an idea of the security offered by the Java language. The actual enforcements of the rules happen not only at compile time but also at class loading and execution time. Compile-time checks performed by the Java compiler flags any violation of access modifier rules, unsafe type castings, use of uninitialized variables and updates of final entities. However, compile-time checks cannot be relied upon to guarantee integrity of mobile code. An attacker could use a "doctored" compiler to generate unsafe code or can modify the generated code using a hex editor or other tool. Java byte-code verifier, an engine that verifies the byte code while loading the individual classes, makes sure that only a valid sequence of byte code gets loaded. Yet another set of checks, such as certain type castings and array bounds checks are performed by the JVM at runtime. The design issues involved in security of language features and byte-code verifier are complex and at times esoteric. Although of great interest to language designers and JVM implementers, these topics have little impact on a programmer, administrator or user. For this reason, we do not dwell upon these any further. What about the vulnerabilities in the implementation of JVM itself? Wouldn't that leave Java applications vulnerable to attacks? This is a valid concern. A number of vulnerabilities have been reported in different implementations of JVM and have been fixed. But this should not cause any alarm. JVM implementations have undergone extensive scrutiny and we can be reasonably confident that most of the serious defects have already been addressed or will be addressed by vendors on a priority basis. Access ControlJava platform provides an elaborate mechanism to specify and enforce access control of certain security sensitive operations with help of a security manager. When a Java program is run by invoking a JVM at command line with the "java classname" command, there is no security manager in force and all code has permission to do whatever the underlying operating system allows. However, you can specify a security manager either at command line or programmatically within the program. A JVM associated with a browser, that runs applets downloaded from various sites, is configured to have a security manager by default. With default settings within a browser, the security manager is responsible to make sure that an applet cannot perform a number of privileged actions including (a) inspect or change a file on the local machine; (b) make a network connection to hosts other than the one from where the applet was downloaded; (c) start another program; (d) load native libraries; (e) get access to certain system property values such as java.class.path, user.dir, user.name, and so on. With a security manager installed, one or more Java classes can be granted permission to perform operations on basis of the following:
Specific permissions can be granted to a collection of classes based on zero (meaning the permissions apply to every class irrespective of its origin, signature or the current user) or more of the above. Java platform defines a wide variety of permission types applicable to different operations. A privilege to carry out any operation is granted by specifying a permission entity within a grant statement of a policy file. A permission entity has three parts: permission type, target name and associated actions. A permission type is defined by a fully qualified Java class name. Target names and associated actions depend on the permission type. Let us understand this with the help of an example: A permission of type java.io.FilePermission could apply to a set of files and directories, i.e., target names, for specific actions such as "read" and/or "write". The permissions can be specified statically in one or more policy files or dynamically at runtime by invoking appropriate methods. Let us look at a policy file fragment that grants read permission to certain files:
grant codebase "file:/home/Pankaj/" {
permission java.io.FilePermission "/home/pankaj/work/-", "read";
};
This statement grants read permission on all the file in the directory tree rooted at /home/pankaj/work to the code in .class files (but not the .jar files) residing in the directory /home/pankaj. This discussion on access control in Java here has been very brief. Hopefully you get an idea of what we are talking about. We return to this important topic in Chapter 5, Access Control. Cryptographic SecurityAs we noted in the first chapter, a number of security features depend on cryptographic operations and related standards. Java platform supports these through various Security APIs. These APIs are part of J2SDK v1.4 and include JCA (Java Cryptography Architecture), Certification Path API, JCE (Java Cryptography Extension) and JSSE (Java Secure Socket Extension). Let us briefly touch on each of these.
Though we devote a significant portion of the book to cryptography APIs, it should be kept in mind that this is not a book on cryptography. We talk about cryptographic concepts, algorithms, APIs, and other aspects only as much as needed for practical security of J2EE-based enterprise applications. |
|
|
< Day Day Up > |
|