10.3 Java Security Framework


10.3.1 Receiver Security SandBox

The advantages of executable content, such as ECMA Script or Java classes, come from the increase in power and flexibility provided by software programs. The essence of the problem is that running programs on an iTV receiver typically gives that program access to certain resources on that receiver. If an iTV receiver that downloads and executes code is not careful to restrict access, untrusted applications may contain malicious programs with the same ability to do mischief as a hacker who had gained access to the receiver. Unfortunately, the solution is not as simple as completely restricting a downloaded program's access to resources: To be useful, a program needs to access certain resources. Thus, if one desires useful and secure executable content, access to resources needs to be carefully controlled. In the context of iTV, the following operations are typically considered sensitive:

  • Disclosure of information about a viewer or the receiver

  • Automatic tuning or selection of program components or applications to launch

  • Grabbing display area (this may override the main video or other applications)

  • Controlling audio rendering (this may disrupt or degrade the viewer's experience)

  • Grabbing focus of remote control events (this may prevent channel changing)

  • Downloading large amounts of data (e.g., video clips) that overwhelm the receiver

  • Accessing a return channel (and possibly the open Internet)

  • Upgrading receivers (this may damage receiver's software)

The Java security framework was designed to address this problem. The original security model provided by the Java platform, known as the sandbox model , existed to provide a very restricted environment in which to run untrusted code obtained from the open network. In the sandbox model local code is trusted to have full access to vital system resources, such as the file system, but downloaded remote code (an applet) is not trusted and can access only the limited resources provided inside the sandbox. A security manager is responsible in this and subsequent platforms for determining which resource accesses are allowed.

Receivers typically comply with the following security rules:

  1. There are a number of enhanced permissions that may only be granted to signed, trusted applications.

  2. There is a minimum sandbox of permissions for unsigned applications, which enumerates all permissions granted to all executing applications, whether trusted or not.

  3. Denying an application a permission that is in the minimum sandbox is to not execute the application at all.

  4. A receiver is expected not to grant any enhanced permission if it is not requested by the application through the permission request file.

10.3.2 Java Cryptography Architecture (JCA)

While powerful, the JCA is not required to be implemented by most approved iTV standards. However, in many cases manufacturers may choose to include its implementation as an option, and its presence may influence the purchase decision of many consumers who are sensitive about their privacy.

The JCA, introduced in JDK 1.1, is a framework API for access to services implemented by pluggable security "providers." It provides support for Digital Signature Algorithms (DSA), MD5, SHA1, key-generation algorithms, conversions between different key representations, simple certificate management (JDK 1.1 did not provide format-specific APIs). Certificate management capabilities include certificate factory support to generate certificates and CRLs from their encodings (Sun implements X.509's). JCA also provides simple key management database or keystore. It also ads a random-number generation algorithm that could be used to support the JCA.

The Java 2 platform introduced the Java Cryptography Extension (JCE) as well as some changes to the JCA; it was separated from JCA due to export control issues. It adds encryption, key exchange, key generation, Message Authentication Code (MAC) and multiple providers (to be distinguished from MAC). It supports fine-grained configurable policies and provides runtime state protection using the ProtectionDomain or CodeSource or Policy classes. It provides a runtime security check algorithm utilizing permission classes and subclasses. A SecurityManager and AccessController are used to define the security sandbox. The notion of Guard and GuardedObjects was introduced as well.

  • SecurityManager : The security manager defines check methods called by system, e.g., checkRead(String filename) . A security policy can be made by creating and instantiating a subclass of the security manager. This subclass needs to be installed using System.setSecurityManager which defines the sandbox; this setting cannot be revoked or replaced . If no security manager is installed, all privileges granted.

  • Bytecode verifier : The bytecode verifier checks class files for validity. It verifies that code has only valid instructions, code does not overflow nor underflow the stack, does not convert data types illegally or forge pointers, accesses objects as correct type, method calls use correct number & types of arguments, and that references to classes use legal names . The goal is to prevent access to underlying machine resources via forged pointers, crashes, or otherwise undefined states. For untrusted classes the verifier is turned on.

  • ClassLoader : The ClassLoader is responsible for instantiating (i.e., loading) classes. Given a class name , the ClassLoader locates its definition. The search process always looks at built-in classes first, and continues according to the search path specified by a class path; the use and behavior of the class- path is not standardized by the JVM specification and it therefore implementation dependent. Every object instance has a reference to the classloader instance that instantiated it. Distinct JavaTV Xlets use different ClassLoader instances.

  • ProtectionDomain : A ProtectionDomain object is created from a CodeSource and a PermissionCollection . It defines the set of permissions granted to classes and allows changing those permission using changes to PermissionCollection objects. Each class belongs to a single ProtectionDomain instance, set at class creation time; that reference cannot be modified. Access to ProtectionDomain reference and the objects restricted and requires RuntimePermission.getProtectionDomain() . A Class and its ProtectionDomain are loaded as follows :

    • Step 1. The class loader has loaded class C1, which requests to instantiate an unloaded class C2

    • Step 2. C1's ClassLoader is called, loads C2's class file, and calls the bytecode verifier

    • Step 3. C2's CodeSource is determined

    • Step 4. The Policy object is given that CodeSource as input and produces a PermissionCollection .

    • Step 5. If an existing ProtectionDomain has same CodeSource and Permissions , it is reused, otherwise a new ProtectionDomain is created;

    • Step 6: Assign C2 to the new protection domain. Note that a ClassLoader can be associated with multiple protection domains in the same way that it is associated with multiple classes.

  • CodeSource class : A CodeSource class is an immutable class created from a source (base) URL and an array of certificates. The implies() method, for testing permission implications, is implemented using partial URL matches and allows policies to use URL patterns.

  • Policy class : A Policy class provides interface to a representation of the security policy. Given a CodeSource , it provides a PermissionCollection . It is typically used during setup of ProtectionDomain to set a class' permissions.

Additional areas of recent development, beyond JCA and JCE include Java Secure Socket Extension (JSSE) and Java Authentication and Authorization Service (JAAS). JSSE Implements SSL. JAAS is based on PAM, which is pluggable authenticators for passwords, smart cards, biometric devices, and so on. The JAAS enables code authors to specify whether authenticators are required, requisite (i.e., stop on failure), sufficient (i.e., not required), or optional. It extends the SecurityManager by introducing user -centric (vs. code-centric) control through granting permissions to a Principal in addition to a CodeSource .

10.3.2.1 Evolution of SecurityManagers

The SecurityManager class contains check methods that perform permission testing, such as checkRead() and checkConnect() . Various methods in the Java libraries call a check method before performing each potentially security-sensitive operation. This coding convention provides the security manager an opportunity to prevent completion of the operation by throwing an exception. A security manager routine simply returns if the operation is permitted, but throws a SecurityException if the operation is not permitted. The only exception to this convention is checkTopLevelWindow() , which returns a boolean value.

The other key methods contained in the SecurityManager class are those related to class loader existence and depth: currentClassLoader() , currentLoadedClass() , inClassLoader() , and classLoaderDepth()

In JDK 1.1, the class java.lang.SecurityManager was an abstract class. The default implementations of the security manager check methods threw exceptions. The class loader and depth-related classes were often implemented in native code. A Java application that needed a security manager had to provide their own implementation with the appropriate concrete implementations of the methods (e.g., check methods) that threw exceptions by default.

Security managers based on the JDK 1.1 applet (and iTV Xlet) security manager model typically based their access control decisions on two factors: Whether or not a class with a class loader was on the stack, and how far down the stack the most recent occurrence of a method from a class defined using a class loader was. For example, a typical 1.1-style security manager might have a checkExit() method like the following:

 public void checkExit(int status) {   switch (status)   case ...:     if (classLoaderDepth() > 2) {                 throw new SecurityException(..);     }     break;   case ...:     if (inClassLoader()) {             throw new SecurityException(..);     }   } } 

Such a checkExit() method would not allow Runtime.exit() to be called in certain situations by throwing an exception. In this specific example, certain execution states do not allow the presence of a class loader at all, whereas other states allow a shallow class loader of up to two stack levels.

JDK 1.2 introduced a number of changes into the class java.lang.SecurityManager to allow it usage of a default security manager. It is no longer an abstract class, and can thus be installed as-is. Most check methods called a new checkPermission() method, which by default calls the method of the same name (checkPermission) in the new AccessController class. Those methods that do not call checkPermission() have reasonable defaults. Methods used in JDK 1.1 to determine if a class loader is on the stack and/or to calculate class loader depth have been modified in JDK 1.2 to ignore system class loaders and security contexts that have been granted java.security.AllPermission .

Since java.lang.SecurityManager is no longer abstract, it can be installed and used as the default security manager, in many ways. For example, some VM implementation allow setting a system property when launching some VM implementations, e.g., java -Djava .security.manager <Application> . Alternatively, an application can install a SecurityManager directly using the call System.setSecurityManager(new SecurityManager()). The behavior of a SecurityManager can be customized by modifying policy files. See the security guide on policy files for more information.

In JDK 1.2, the SecurityManager methods related to class loaders and class loader depth are not called by any of the check methods, and they are deprecated. They should not be used by any new security managers, and it is recommended that their use be eliminated from existing security managers as well. However, they are left in for backward compatibility and they have been modified in an attempt to enable old 1.1-style security managers to still work under JDK 1.2, without modification. For example, the constructor for java.security.SecureClassLoader() has an explicit call to SecurityManager.checkCreateClassLoader() even though the constructor for its superclass ( ClassLoader ) also does. If the check was not placed in the constructor for SecureClassLoader , then a 1.1-style security manager would allow untrusted code to extend SecureClassLoader and construct class loaders, as the class loader depth would always be greater than 2.

10.3.3 Java 2 Runtime Security Check

Most iTV standards do not support Java 2 and therefore do not support the security checking framework described next . However, this does not preclude a specific iTV implementation from supporting this feature.

Runtime security checks are one of the capabilities enabled by the use of a JVM to execute Java bytecode. The design goal of this framework was to support actions on behalf of another, for example, one thread posts an event to another, as well as delayed actions or background operations (e.g., cron job). The runtime security check is based on the notion of execution context. The latter could be accessed using the getContext() method, which takes a snapshot of current execution context (i.e., stack trace). The result includes snapshoting ancestor threads stored in the AccessControlContext object.

The runtime security check is performed as follows. If method M requires permission P, then M's implementation must call current SecurityManager.checkPermission(P) , which by default, calls the AccessController . For each call stack entry, the runtime security check performs the following:

  • If the caller's ProtectionDomain lacks P, then throw an exception and fail.

  • If the caller called doPrivileged() without context, then return and succeed.

  • If the caller called doPrivileged() with context, then check that context and return (i.e., succeed) if context permits P; otherwise, throw an exception and fail.

For example, consider the use of multiple ProtectionDomains . Let Instance1 of Class1 be associated with ProtectionDomain M1 , and assume that Class1 calls Instance2 of Class2, which is associated with ProtectionDomain M2 . Class2 , in turn , calls a system method of Class3 in a system ProtectionDomain M3 . With the last call, M3 asks for a permission check. Permissions are checked against the ProtectionDomains for the system object Class3 , then, going up the call stack, asks for a check on Class2 , and Class1 .

The implications of this algorithm are as follows: default privileges are the intersection (i.e., minimum) of all class' permissions in call tree. A call to doPrivileged() enables all class' privileges; the node calling doPrivileged() is a root of a call-tree under which the default permissions are unrelated to that of its parent. When doPrivileged() is called without a context, all privileges are enabled. When called with a context, enables only those privileges that are given to the context; this is safe because the resulting privileges are always subsumed or equal to those of that context.

10.3.4 Guarded Objects

GuardedObject s are used to protect methods and references against unauthorized access. iTV standards do not support Java 2 and therefore do not support guarded objects. However, this does not preclude a specific iTV implementation from supporting this feature.

A GuardedObject encapsulates a target object and a Guard object, such that access to the target object is possible only if the Guard object allows it. Once an object is encapsulated by a GuardedObject , access to that object is controlled by the getObject() method, which invokes the checkGuard() method on the Guard object that is guarding access.



ITV Handbook. Technologies and Standards
ITV Handbook: Technologies and Standards
ISBN: 0131003127
EAN: 2147483647
Year: 2003
Pages: 170

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net