JavaTM安全体系结构(JDK1.2)
3. 许可和安全策
3.1 许可类?
许可类表示了对系统资源的访问。java.security.Permission类是一个抽象的类,且在适当的时候可生成子类以表示特定的访问。
-
-
作为许可的一个例子,下列代码可被用来生成一个阅读在/tmp目录下名为“abc”的文件的许可?br>
-
perm = new java.io.FilePermission ("/tmp/abc", "read");
-
新许可类可通过继承Permission类或它的子类(如java.security.BasicPermission) 来生成的。已成为子类的许可(不是BasicPermission)通常都属于它们自己的包。因此,FilePermission可在java.io.package中找到。
-
一个重要的并需要被每个许可新类实现的抽象方法是implies方法。一般来说,“a implies b”意味着如果你被授予了许可"a",那么你也就自然地被授予了许可"b"。这在访问控制决策中是十分重要的。
-
与抽象类java.security.Permission一起的是被称为java.security.PermissionCollection的抽象类和叶子类java.security.Permissions。
-
java.security.PermissionCollection类表示了单一类别的(如文件许可)Permission对象的集合(例如,允许复制的一个集),以便于分组。在许可能够被以任何顺序添加到PermissionCollection对象的情况下(如为文件许可),当implies功能被调用时,PermissionCollection对象能够确保其后语义的正确性是至关重要的。
-
java.security.Permissions类表示了Permission对象的集合的集合,或换句话说,是异类许可的超级集合。
-
应用程序可添加系统支持的许可的新类型。添加此种特殊应用程序的许可的方法将在后面讨论。
-
现在,我们来说明所有内置许可的句法和语义。
3.1.1 java.security.Permission?
-
这个抽象类是所有许可的祖先,它为所有许可定义了所需的基本功能。
-
典型地,每个许可实例通过将一个或多个字符串参数传递给构造函数而被生成。在有两个参数的普通情况下,第一个参数通常是“目标名”(如作为许可目标的一个文件的名称),第二个参数是动作(如对一个文件的“阅读”动作)。一般的,一组动作可用逗号分隔的复合串来一起指定。
3.1.2 java.security.PermissionCollection
-
这个类掌握了许可的一个同类收集。换言之,类的每个实例仅掌握同类型的许可。
3.1.3 java.security.Permissions
-
设计这个类是为了掌握许可的异类收集。基本上,它是java.security.PermissionCollection对象的收集。
3.1.4 java.security.UnresolvedPermission
-
在正常情况下,一个安全策略的内部状态是由与每个代码源相关联的许可对象来表示的。然而,鉴于Java技术的动态性,当该策略被启动时,那些用来实现特定许可类的实际代码可能还没有在Java环境中被装载和定义。例如,一个基准许可类可能在JAR文件中,而该文件将稍后再装载。
-
UnresolvedPermission类被用来掌握这种“未解决的”的许可。类似的,java.security.UnresolvedPermissionCollection类储存UnresolvedPermission许可的收集。
-
在对一个以前未解决的类型(但它的类已经被装载)的许可的访问控制检查中,未解决的许可是“解决的”,并且作出了适当的访问控制决策。即:如果可能的话,基于UnresolvedPermission的信息,适当的类的新的对象被实例化,这个新的对象代替了UnresolvedPermission。
-
如果此时许可仍然是不可解决的,则该许可被认为是无效的,就象在一个安全策略中,它从未被授予过一样。
3.1.5 java.io.FilePermission
-
这个类的目标可用下列方法来说明,在这里,目录和文件名是不包括空格的字符串。
file firectory (与directory/一样) firectory/file firectory/* (在目录directory下的所有文件) ? (在当前目录中的所有文件) firectory/- (在目录directory 下的文件系统中的所有文件) ? (在当前目录下的文件系统中的所有文件) 《ALL FILES》" (在文件系统中的所有文件)
?
-
注意“”是一个用来表示系统中所有文件的特殊字符串。在Unix系统中,它包括了根目录下的所有文件;在MS-DOS系统中,它包括了在所有驱动器中的所有文件。
-
这个类的动作是:读、写、删除和执行(read, white, delete and execute)。以下是创建文件许可的有效代码样本:
port java.io.FilePermission; FilePermission p = new FilePermission("myfile", "read,write"); FilePermission p = new FilePermission("/home/gong/", "read"); FilePermission p = new FilePermission("/tmp/mytmp", "read,delete"); FilePermission p = new FilePermission("/bin/*", "execute"); FilePermission p = new FilePermission("*", "read"); FilePermission p = new FilePermission("/-", "read,execute"); FilePermission p = new FilePermission("-", "read,execute"); FilePermission p = new FilePermission("《ALL FILES》", "read"); 在这个类中的implies方法可正确地说明文件系统。例如, FilePermission("/-","read,execute")隐含 FilePermission("/home/gong/public_html/index.html", "read"); FilePermission("/bin/*", "execute")隐含 FilePermission("bin/emacs19.13", "execute")。
-
注:这些字符串的大部分都是以依赖于平台的格式给出。例如,要表示对在Windows系统C驱动器中的 "temp" 目录下名为 "foo"的文件的阅读访问,你可以使用:
-
FilePermission p = new FilePermission ("c://temp//foo", "read");
-
这里使用双反斜线来代表单反斜线是必要的。因为字符串是由一个tokenizer来处理的(java.io.StreamTokenizer),它允许 "/" 当作换行字符串来使用(例如, "/n"表示一个新的行),因此,我们需要用双反斜线来替代单反斜线的功能。在tokenizer对上述FilePermission目标字符串做过处理之后,再将双反斜线转换为单反斜线,最后结果是实际路径:
-
"c:/temp/foo"
-
在全局文件描述语言出现之前,字符串应该以依赖于平台的格式给出,这一点是必要的。还要注意的是,通配符(如 "*"和 "-"等)的使用影响了特殊文件名的使用。我们认为这是一个可以容忍的小限制。最后,要注意 "/-" 和 "《ALL FILES》" 在Unix系统中是同一个目标,它们都表示整个文件系统(如果有的话,它们也可表示多个文件系统);在其它操作系统中(如MS Windows,MacOS),这两个目标可能是不同的。
-
还要注意的一点是,象下列代码中仅指出目录和 "read" 动作的目标名,表示你只被允许列出那个目录中的文件名,而不能读它们。
-
FilePermission p = new FilePermission ("/home/gong", "read");
-
要允许对文件的阅读访问,你必须指出明确的文件名,或 "*",或 "- ",如下所示:?br>
FilePermission p = new FilePermission ("/home/gong/myfile", "read"); FilePermission p = new FilePermission ("/home/gong/*", "read"); FilePermission p = new FilePermission ("/home/gong/-", "read");
-
最后注意的是,代码总是自动具有对阅读位于与其相同的URL位置上的文件的许可,包括那个位置上的子目录;这不需要明确的许可。
3.1.6 java.net.SocketPermission
-
这个类表示通过sockets对一个网络的访问。这个类的目标可给为 "hostname:port_range",这里的hostname可用下列方式给出:
-
hostname (一个主机) IP address (一个主机) localhost (本地机) "" (相同于localhost") hostname.domain (在域domain中的一个主机) hostname.subdomain.domain *.domain (在域domain中的所有主机) *.subdomain.domain * (所有主机) ?/pre>?
-
也就是说,主机被表示为一个DNS名,或数字IP地址,或 "localhost"(为本地的机器),或 ""(它与指定的 "localhost" 等同)。
-
通配符 "*"可能会在DNS名称主机规范中使用一次,在这种情况下,它必须被放置在最左边,如: "*.sun.com"。 ?br>
-
port_range可按如下方式给出:
-
N (一个单一的端口)
-
N- (端口N及以上的所有端口)
-
-N (端口N及以上下的所有端口)
-
N1-N2 (N1和N2之间的所有端口, 包括N1和N2)
-
这里的N、N1和N2为非负整数,范围为0至65535(2^16-1)。 ?br>
-
在socket上的动作有accept(接受), connect(连接), listen(侦听)和resolve(分辨) (它们是基本的DNS查询)。请注意,动作 "resolve"是由 "accept"、 "connect"和 "listen"所暗指的,也就是说,那些可以侦听、接受来自主机的连接或启动一个指向另一主机的连接的动作的类,应该能够查询远程主机的名称。
以下是socket许可的一些实例&#