Java安全策略(Policy)

根据以前的几篇文章我们知道,Java 2 平台安全体系结构背后的基本原理可以总结如下:

一个系统级的安全策略定义了按以保护域(protection domains.)方式组织的执行代码的访问权限(按照应用程序的需要)。安全策略用于访问控制检查,这是由 JVM 在运行时执行的。

在 Java 2 平台中,所有的代码,不管它是本地代码还是远程代码,都可以由策略来控制,此基础上构建的 Java 2 平台安全策略设计为根据 ProtectionDomain 授权访问权限,而不是向单个的一段运行代码授权这种权限。因此,每一个类或者对象“属于”一个 ProtectionDomain ,安全策略对这个保护域授予了某种访问权限。一个特定的 ProtectionDomain 封装了一组类(例如,所有从特定位置上装载、并用特定密钥签名的所有类),它们的实例将会授予同样的一组权限。


保护域和代码源

显然,一定要能惟一地标识一段运行代码以保证它的访问权限没有冲突。运行代码的惟一标识属性共有两项:代码的来源(代码装载到内存所用的 URL)和代码的 signer 实体(由对应于运行代码的数字签名的一组公共密钥指定)。这两种特性的组合成运行代码的 CodeSource 。现在可以提供 ProtectionDomain 的更严格定义了: ProtectionDomain 是一组 CodeSource 及其访问权限。

Java 运行时通过名为 java.security.Policy 的类(的具体扩展)设置 ProtectionDomain 与授予它的权限之间的映射。这个类的默认扩展是 sun.security.provider.PolicyFile(参考jre下的java.security文件) 。它 从一个文件中获得 CodeSource (由位置 URL 和 signer 标识别名)与授予它的权限之间的映射。可以通过环境变量 java.security.policy 将这个文件的位置作为输入提供给 JVM。 Policy 类提供了一个名为 getPermissions() 的方法,可以调用它以获得授予特定 CodeSource 的一组权限。

一个类与 其 ProtectionDomain 之间的映射是在类第一次装载时由一个名为 SecureClassLoader 的特殊类装载设置的。在 Java 2 平台 SDK 1.4 中, ProtectionDomain 可以同时封装(通过其构造函数传递的)静态权限和动态权限,以前版本权限必须在构建时就已经知道。



运行时访问检查

由一个名为 SecurityManager 的类负责实施系统安全策略。在默认情况下不安装安全管理器,必须通过一个在启动时传递给 JVM 的、名为 java.security.manager 的环境变量显式地指定。任何应用程序都可找到安装的 SecurityManager 并调用它相应的 check<XXX> 方法。如果所要求的权限在给定运行时上下文中是授予的,那么调用将无声地返回。如果权限没有授予,那么将抛出一个 java.security.AccessControlException 。
Java 2 平台安全体系结构通过引入一个名为 AccessController ,对 SecurityManager 类进行的所有 check<XXX> 方法调用都解释为相应的 Permission 对象,并将它作为输入参数传递给 AccessController 类的 checkPermission() 方法



访问检查方案

权限的算法是要计算所有权限的交集,确定权限集的交集的算法是在 AccessController 类的 checkPermission 方法中间接实现的,属于能力更低的域的类不能通过调用属于能力更高的域的类而变得更强大,而属于能力更高的域中的类会在调用能力更低的类时损失其能力



Policy File Syntax

学习时参照"jre"lib"security"java.policy文件

一个Policy文件实质上是一个记录列表,它可能含有一个“keystore”记录,以及含有零个或多个“grant”记录

其格式如下:
keystore "some_keystore_url", "keystore_type", "keystore_provider";
keystorePasswordURL "some_password_url";

“keystore”是一个私有密钥(private keys)数据库和相应的数字签名,例如X.509证书。Policy文件中可能只有一条keystore记录(也可能不含有该记录),它可以出现在文件中grant记录以外的任何地方。Policy配置文件中指定的keystores用于寻找grant记录中指定的、签名者的公共密钥(public keys),如果任何grant记录指定签名者(signer_names),那么,keystore记录必须出现在policy配置文件中。

 "some_keystore_url"是指keystore的URL位置,"keystore_type"是指keystore的类型。第二个选项是可选项,如果没有指定,该类型则假定由安全属性文件(java.security)中的"keystore.type"属性来确定。keystore类型定义了keystore信息的存储和数据格式,用于保护keystore中的私有密钥和keystore完整性的算法。Sun Microsystems支持的缺省类型为“JKS”。

grant signedBy "signer_names", codeBase "URL",
        principal principal_class_name "principal_name",
        principal principal_class_name "principal_name",
         {

      permission permission_class_name "target_name", "action", 
          signedBy "signer_names";
      permission permission_class_name "target_name", "action", 
          signedBy "signer_names";
      
  };

在Policy文件中的每一个grant记录含有一个CodeSource(一个指定的代码)及其permission(许可)。

Policy文件中的每一条grant记录遵循下面的格式,以保留字“grant”开头,表示一条新的记录的开始,“Permission”是另一个保留字,在记录中用来标记一个新的许可的开始。每一个grant记录授予一个指定的代码(CodeBase)一套许可(Permissions)。

permission_class_name必须是一个合格并存在的类名,例如java.io.FilePermission,不能使用缩写(例如,FilePermission)。

target_name用来指定目标类的位置,action用于指定目标类拥有的权限。
target_name可以直接指定类名(可以是绝对或相对路径),目录名,也可以是下面的通配符:
directory/* 目录下的所有文件
*当前目录的所有文件
directory/-目录下的所有文件,包括子目录
- 当前目录下的所有文件,包括子目录
《ALL FILES》文件系统中的所有文件
对于java.io.FilePermission,action可以是:read, write, delete和execute。
对于java.net.SocketPermission,action可以是:listen,accept,connect,read,write。

The exact meaning of a codeBase value depends on the characters at the end. A codeBase with a trailing "/"
 matches all class files (not JAR files) in the specified directory. A codeBase with a trailing "/*" matches
 all files (both class and JAR files) contained in that directory. A codeBase with a trailing "/-" matches
all files (both class and JAR files) in the directory and recursively all files in subdirectories contained
 in that directory. The following table illustrates the different cases.
/    表示所有的class文件(不包括Jar,不包括子目录)
/*  
表示所有的class文件(包括Jar,不包括子目录
/-   表示所有的class文件(包括Jar,包括子目录


Policy文件中的属性扩展(Property Expansion)

属性扩展与shell中使用的变量扩展类似,它的格式为:
permission java.io.FilePermission
"${user.home}", "read";

具体详细使用请参考:Policy官方文档:Default Policy Implementation and Policy File Syntax


参考资源:
http://www.ibm.com/developerworks/cn/java/j-javaauth/
http://www.ibm.com/developerworks/cn/java/j-jaas/
http://java.sun.com/j2se/1.5.0/docs/guide/security/PolicyFiles.html#DefaultImpl
http://www.infosecurity.org.cn/article/websec/java/23218.html