|
Code Access Security: Permissions
Code-access permissions represent authorization to access a protected resource or perform a dangerous operation, and form a foundation of CAS. They have to be explicitly requested from the caller either by the system or by application code, and their presence or absence determines the appropriate course of action.
Both Java and .NET supply an ample choice of permissions for a variety of system operations. The runtime systems carry out appropriate checks when a resource is accessed or an operation is requested. Additionally, both platforms provide the ability to augment those standard permission sets with custom permissions for protection of application-specific resources. Once developed, custom permissions have to be explicitly checked for (demanded) by the application's code, because the platform's libraries are not going to check for them.
.NET defines a richer selection here, providing permissions for role-based checks (to be covered in the "User Access Security" section of Part 4) and evidence-based checks. An interesting feature of the latter is the family of Identity permissions, which are used to identify an assembly by one of its traits -- for instance, its strong name (StrongNameIdentityPermission). Also, some of its permissions reflect close binding between the .NET platform and the underlying Windows OS (EventLogPermission, RegistryPermission). IsolatedStoragePermission is unique to .NET, and it allows low-trust code (Internet controls, for instance) to save and load a persistent state without revealing details of a computer's file and directory structure. Refer to MSDN documentation for the list of .NET Code Access and Identity permissions.
Adding a custom code access permission requires several steps. Note that if a custom permission is not designed for code access, it will not trigger a stack walk. The steps are:
Optionally, inherit from CodeAccessPermission (to trigger a stack walk).
Implement IPermission and IUnrestrictedPermission.
Optionally, implement ISerializable.
Implement XML encoding and decoding.
Optionally, add declarative security support through an Attribute class.
Add the new permission to CAS Policy by assigning it to a code group.
Make the permission's assembly trusted by .NET framework.
A sample of custom code-access permission can be found in the demo application. Also, check MSDN for additional examples of building and registering a custom permission with declarative support.
.NET permissions are grouped into NamedPermissionSets. The platform includes the following non-modifiable built-in sets: Nothing, Execution, FullTrust, Internet, LocalIntranet, SkipVerification. The FullTrust set is a special case, as it declares that this code does not have any restrictions and passes any permission check, even for custom permissions. By default, all local code (found in the local computer directories) is granted this privilege.
The above fixed permission sets can be demanded instead of regular permissions:
[assembly:PermissionSetAttribute(
SecurityAction.RequestMinimum,
Name="LocalIntranet")]
In addition to those, custom permission sets may be defined, and a built-in Everything set can be modified. However, imperative code-access checks cannot be applied to varying permission sets (i.e., custom ones and Everything). This restriction is present because they may represent different permissions at different times, and .NET does not support dynamic policies, as it would require re-evaluation of the granted permissions.
Permissions, defined in Java, cover all important system features: file access, socket, display, reflection, security policy, etc. While the list is not as exhaustive as in .NET, it is complete enough to protect the underlying system from the ill-behaving code. See the JDK documentation for the complete list, and the Java permissions guide for more detailed discussions of their meaning and associated risks.
Developing a custom permission in Java is not a complicated process at all. The following steps are required:
Extend java.security.Permission or java.security.BasicPermission.
Add new permission to the JVM's policy by creating a grant entry.
Obviously, the custom permission's class or JAR file must be in the CLASSPATH (or in one of the standard JVM directories), so that JVM can locate it.
Below is a simple example of defining a custom permission. More examples can be found in the demo application or in the Java tutorial:
//permission class
public class CustomResPermission extends Permission {
public CustomResPermission (String name,
String action) {
super(name,action);
}
}
//library class
public class AccessCustomResource {
public String getCustomRes() {
SecurityManager mgr =
System.getSecurityManager();
if (mgr == null) {
//shouldn't run without security!!!
throw new SecurityException();
} else {
//see if read access to the resource
//was granted
mgr.checkPermission(
new CustomResPermission("ResAccess","read"));
}
//access the resource here
String res = "Resource";
return res;
}
}
//client class
public class CustomResourceClient {
public void useCustomRes() {
AccessCustomResource accessor =
new AccessCustomResource();
try {
//assuming a SecurityManager has been
//installed earlier
String res = accessor.getCustomRes();
} catch(SecurityException ex) {
//insufficient access rights
}
}
}
J2EE reuses Java's permissions mechanism for code-access security. Its specification defines a minimal subset of permissions, the so-called J2EE Security Permissions Set (see section 6.2 of the J2EE.1.4 specification). This is the minimal subset of permissions that a J2EE-compliant application might expect from a J2EE container (i.e., the application does not attempt to call functions requiring other permissions). Of course, it is up to individual vendors to extend it, and most commercially available J2EE application servers allow for much more extensive application security sets.
Note: .NET defines a richer sets-based permission structure than Java. At the same time, .NET permissions reveal their binding to the Windows OS. |
|