Java策略文件 – 拒绝对代码库的权限
在Java策略文件中, grant codeBase
语法指定应授予哪些代码库哪些权限。 例如,
grant codeBase“file:/ C:/abc.jar”{permission java.security.AllPermission; };
将AllPermission
授予abc.jar中的代码
以类似的方式,有没有办法deny
特定语法的权限? 喜欢这个:
deny codeBase“file:/ C:/def.jar”{permission java.io.FilePermission; };
以便def.jar
中的代码获得除FilePermission之外的所有其他权限?
这有可能吗?
我知道这可以使用SecurityManager
类轻松完成,但我只想知道是否可以通过仅使用策略文件来实现。
没有。政策文件没有这样的实现。 如果你真的很绝望,你可以编写自己的系统。
我意识到这已经晚了一年,但我想我正在尝试做类似的事情。
有一种方法可以设置运行时权限,以便Java不会授予全局权限。 然后,您只能指定要为您的应用授予的权限。 关键是使用以下选项运行您的应用程序。
java -Djava.security.manager -Djava.security.policy==policyFile.txt MyClass
请注意,double等于-Djava.security.policy==policyFile.txt
。 double equals ==
表示仅使用命名文件中的权限而不是单个等号-Djava.security.policy=policyFile.txt
,这意味着除了inheritance的全局权限之外还使用这些权限。
然后创建一个策略文件,不包括您要拒绝的权限:
// policyFile.txt grant codeBase "file:/C:/abc.jar" { // list of permissions minus the ones you want to deny // for example, the following would give the application // ONLY AudioPermission and AWTPermission. Other // permissions such as java.io.FilePermission would be // denied. permission javax.sound.sampled.AudioPermission; permission java.awt.AWTPermission; }
您可以使用Prograde库,它使用拒绝规则实现策略文件。
将以下Maven依赖项添加到您的应用程序
net.sourceforge.pro-grade pro-grade 1.0
然后使用标准系统属性为您的应用程序启用它:
-Djava.security.manager=net.sourceforge.prograde.sm.ProgradeSecurityManager -Djava.security.policy==/path/to/your/application.policy
或者您可以在代码中以编程方式替换Policy实现:
System.setProperty("java.security.policy","/path/to/your/application.policy"); Policy.setPolicy(new ProgradePolicyFile());
策略文件的语法与标准实现类似,但您可以使用deny
而不是grant
,也可以使用关键字priority
更改优先priority
(默认值为"deny"
– 保持向后兼容)。
例如,你可以做某事。 喜欢:
grant { permission java.lang.RuntimePermission "*"; }; deny { permission java.lang.RuntimePermission "exitVM.*"; };
其他例子在这里 。
实现拒绝规则支持的最少参与方法之一是:
- 定义一个“负”的
Permission
子类,它包含一个常规的肯定权限并否定它; 和 - 包装默认
Policy
,使其(包装器)理解这些权限。
DeniedPermission
类
package com.example.q5003565; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.security.BasicPermission; import java.security.Permission; import java.security.UnresolvedPermission; import java.text.MessageFormat; /** * A representation of a "negative" privilege. * * A DeniedPermission
, when "granted" to some ProtectionDomain
, represents * a privilege which cannot be exercised, regardless of any positive permissions * (AllPermission
included) possessed. In other words, if a set of granted permissions, * P, contains a permission of this class, D, then the set of effectively granted * permissions is
*
* { Pimplied - Dimplied }. *
* * Each instance of this class encapsulates a target permission, representing the * "positive" permission being negated. *
* Denied permissions employ the following naming scheme:
*
* <target_class_name>:<target_name>(:<target_actions>)
*
* where: * * - <target_class_name> is the fully qualified name of the target permission's * class,
* - <target_name> is the {@linkplain #getName() name} of the target * permission,
* - (<target_actions>) is, optionally, the {@linkplain #getActions() actions * string} of the target permission, and
* - the ':' character stands for itself.
*
* A denied permission, having a target permission t, is said to * {@linkplain #implies(Permission) imply} another permission p, iff: * * - p is not itself a denied permission, and
(t.implies(p) == true)
, * or * - p is a denied permission, with a target t1, and *
(t.implies(t1) == true)
. *
* * It is the responsibility of the policy decision point (eg, the Policy
provider) to * take denied permission semantics into account when issuing authorization statements. *
*/ public final class DeniedPermission extends BasicPermission { private static final String NULL_STR_ARG = "", EMPTY_STR_ARG = " "; private static final long serialVersionUID = 2102974454790623344L; private final Permission target; /** * Instantiates a DeniedPermission
that encapsulates a target permission of the * indicated class, specified name and, optionally, actions. * * @throws IllegalArgumentException * if: * * targetClassName
is null
, the empty string, does not * refer to a concrete Permission
descendant, or refers to * DeniedPermission.class
or UnresolvedPermission.class
. * targetName
is null
. * targetClassName
cannot be instantiated, and it's the caller's fault; * eg, because targetName
and/or targetActions
do not adhere * to the naming constraints of the target class; or due to the target class not * exposing a (String name)
, or (String name, String actions)
* constructor, depending on whether targetActions
is null
or * not. *
* @throws SecurityException * if a SecurityManager
, sm
, is installed, and the invocation * sm.checkPackageAccess(targetClassPackageName)
(where * targetClassPackageName
is the package of the class referred to * by targetClassName
) denies access. */ public static DeniedPermission newDeniedPermission(String targetClassName, String targetName, String targetActions) { if (targetClassName == null || targetClassName.trim().isEmpty() || targetName == null) { throw new IllegalArgumentException("[targetClassName] and [targetName] must not be null or empty."); } StringBuilder sb = new StringBuilder(targetClassName).append(":").append(targetName); if (targetName != null) { sb.append(":").append(targetName); } return new DeniedPermission(sb.toString()); } /** * Instantiates a DeniedPermission
that encapsulates the given target permission. * * @throws IllegalArgumentException * if target
is null
, a DeniedPermission
, or an * UnresolvedPermission
. */ public static DeniedPermission newDeniedPermission(Permission target) { if (target == null) { throw new IllegalArgumentException("[target] must not be null."); } if (target instanceof DeniedPermission || target instanceof UnresolvedPermission) { throw new IllegalArgumentException("[target] must not be a DeniedPermission or an UnresolvedPermission."); } StringBuilder sb = new StringBuilder(target.getClass().getName()).append(":").append(target.getName()); String targetActions = target.getActions(); if (targetActions != null) { sb.append(":").append(targetActions); } return new DeniedPermission(sb.toString(), target); } private static Permission constructTargetPermission(String targetClassName, String targetName, String targetActions) { Class> targetClass; try { targetClass = Class.forName(targetClassName); } catch (ClassNotFoundException cnfe) { if (targetClassName.trim().isEmpty()) { targetClassName = EMPTY_STR_ARG; } throw new IllegalArgumentException( MessageFormat.format("Target Permission class [{0}] not found.", targetClassName)); } if (!Permission.class.isAssignableFrom(targetClass) || Modifier.isAbstract(targetClass.getModifiers())) { throw new IllegalArgumentException(MessageFormat .format("Target Permission class [{0}] is not a (concrete) Permission.", targetClassName)); } if (targetClass == DeniedPermission.class || targetClass == UnresolvedPermission.class) { throw new IllegalArgumentException( "Target Permission class must not be a DeniedPermission itself, nor an UnresolvedPermission."); } Constructor> targetCtor; try { if (targetActions == null) { targetCtor = targetClass.getConstructor(String.class); } else { targetCtor = targetClass.getConstructor(String.class, String.class); } } catch (NoSuchMethodException nsme) { throw new IllegalArgumentException(MessageFormat.format( "Target Permission class [{0}] (String name) or (String name, String actions) constructor.", targetClassName)); } try { return (Permission) targetCtor .newInstance(((targetCtor.getParameterCount() == 1) ? new Object[] { targetName } : new Object[] { targetName, targetActions })); } catch (ReflectiveOperationException roe) { if (roe instanceof InvocationTargetException) { if (targetName == null) { targetName = NULL_STR_ARG; } else if (targetName.trim().isEmpty()) { targetName = EMPTY_STR_ARG; } if (targetActions == null) { targetActions = NULL_STR_ARG; } else if (targetActions.trim().isEmpty()) { targetActions = EMPTY_STR_ARG; } throw new IllegalArgumentException(MessageFormat.format( "Could not instantiate target Permission class [{0}]; provided target name [{1}] and/or target [{2}] actions potentially erroneous.", targetClassName, targetName, targetActions), roe); } throw new RuntimeException(MessageFormat.format( "Could not instantiate target Permission class [{0}] - an unforeseen error occurred, see attached cause for details.", targetClassName), roe); } } /** * Instantiates a DeniedPermission
that encapsulates a target permission of the class, * name and, optionally, actions, collectively provided as the name
argument. * * @throws IllegalArgumentException * if: * * name
's target permission class name component is empty, does not * refer to a concrete Permission
descendant, or refers to * DeniedPermission.class
or UnresolvedPermission.class
. * name
's target name component is empty
* - the target permission class cannot be instantiated, and it's the caller's fault; * eg, because
name
's target name and/or target actions component(s) do * not adhere to the naming constraints of the target class; or due to the target class * not exposing a (String name)
, or * (String name, String actions)
constructor, depending on whether the * target actions component is empty or not. *
* @throws SecurityException * if a SecurityManager
, sm
, is installed, and the invocation * sm.checkPackageAccess(targetClassPackageName)
* (where targetClassPackageName
is the package of the class referred to * by name
's target name component) denies access. */ public DeniedPermission(String name) { super(name); String[] comps = name.split(":"); if (comps.length < 2) { throw new IllegalArgumentException(MessageFormat.format("Malformed [name] argument: {0}", name)); } this.target = constructTargetPermission(comps[0], comps[1], ((comps.length < 3) ? null : comps[2])); } private DeniedPermission(String name, Permission target) { super(name); this.target = target; } /** * Checks whether the given permission is implied by this one, as per the * {@linkplain DeniedPermission overview}. */ @Override public boolean implies(Permission p) { if (p instanceof DeniedPermission) { return target.implies(((DeniedPermission) p).target); } return target.implies(p); } /** * Returns this denied permission's target permission. */ public Permission getTargetPermission() { return target; } }
DenyingPolicy
类
package com.example.q5003565; import java.security.AccessController; import java.security.CodeSource; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Permission; import java.security.PermissionCollection; import java.security.Policy; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.UnresolvedPermission; import java.util.Enumeration; /** * Wrapper that adds rudimentary {@link DeniedPermission} processing capabilities to the standard * file-backed
Policy
. */ public final class DenyingPolicy extends Policy { /* * doPrivileged needed just in case there's already a SecurityManager installed at class loading * time. */ private static final ProtectionDomain OWN_PD = AccessController .doPrivileged((PrivilegedAction) DenyingPolicy.class::getProtectionDomain); private final Policy defaultPolicy; { try { // will fail unless the calling acc has SecurityPermission "createPolicy.javaPolicy" defaultPolicy = Policy.getInstance("javaPolicy", null, "SUN"); } catch (NoSuchProviderException | NoSuchAlgorithmException e) { throw new RuntimeException("Could not acquire default Policy.", e); } } @Override public PermissionCollection getPermissions(CodeSource codesource) { return defaultPolicy.getPermissions(codesource); } @Override public PermissionCollection getPermissions(ProtectionDomain domain) { return defaultPolicy.getPermissions(domain); } /** * @return true
iff: **
*/ @Override public boolean implies(ProtectionDomain domain, Permission permission) { if (OWN_PD.equals(domain)) { /* * Recursive invocation due to a privilege-requiring method we invoked. If you're uncomfortable with * this, get rid of it and grant (via .policy) a RuntimePermission "accessClassInPackage.*" to * OWN_PD. */ return true; } if (permission instanceof DeniedPermission) { /* * At the policy decision level, DeniedPermissions can only themselves imply, not be implied (as * they take away, rather than grant, privileges). Returning true for a deny rule would be * more confusing than convenient. */ return false; } if (!defaultPolicy.implies(domain, permission)) { // permission not granted--no need to check whether denied return false; } /* * Permission granted--now check whether there's an overriding DeniedPermission. The following * assumes that defaultPolicy (its wrapped PolicySpi) is a sun.security.provider.PolicySpiFile * (other implementations might not support #getPermissions(ProtectionDomain) * and/or handle resolution of UnresolvedPermissions differently). */ Enumeration- *
permission
is not an instance of *DeniedPermission
,- an
*implies(domain, permission)
invocation on the system-default *Policy
yieldstrue
, and- *
permission
is not implied by anyDeniedPermission
s * having potentially been assigned todomain
.perms = defaultPolicy.getPermissions(domain).elements(); while (perms.hasMoreElements()) { Permission p = perms.nextElement(); /* * DeniedPermissions will generally remain unresolved, as no code is expected to check whether other * code has been "granted" such a permission. */ if (p instanceof UnresolvedPermission) { UnresolvedPermission up = (UnresolvedPermission) p; if (up.getUnresolvedType().equals(DeniedPermission.class.getName())) { // force resolution defaultPolicy.implies(domain, up); // evaluate right away, to avoid reiterating over the collection p = AccessController.doPrivileged( (PrivilegedAction ) () -> new DeniedPermission(up.getUnresolvedName())); } } if (p instanceof DeniedPermission && p.implies(permission)) { // permission denied return false; } } // permission granted return true; } @Override public void refresh() { defaultPolicy.refresh(); } }
用法
只是将DeniedPermission
嵌入普通的旧授权规则中; 例如,以下规则将授予除some.jar的类以及以“user。”开头的名称读取系统属性的能力。
grant codeBase "file:/home/your_user/classpath/some.jar" { permission java.security.AllPermission; permission com.example.q5003565.DeniedPermission "java.util.PropertyPermission:user.*:read"; };
然后通过Policy.setPolicy(new DenyingPolicy());
安装Policy.setPolicy(new DenyingPolicy());
。
警告:虽然在语义上是正确的,正如之前的答案评论中提到的,上面的例子是无效的,因为它仍然授予危险权限,例如SecurityPermission "setPolicy"
,它隐含地允许沙盒代码做任何它喜欢的事情,包括禁止的操作由DeniedPermission
。 为了防止这种情况发生,而不是从AllPermission
减去权限,请考虑从AllSafePermission
减去AllSafePermission
,其中AllSafePermission
被定义为除了已知沙箱失败权限1 之外的所有内容。
笔记
- 任何权限都可以被拒绝权限包装,只要它遵循标准目标名称 - 操作约定,公开
(String)
和/或(String, String)
构造函数,并适当地覆盖implies(Permission)
。 - 要一次拒绝多个权限:
- 创建一个普通的权限子类,
implies
要被拒绝的权限。 - “授予”拒绝权限,反过来引用策略配置中的实现实例。
- 创建一个普通的权限子类,
-
DenyingPolicy
不会阻止静态分配给保护域的权限(例如默认授予的RuntimePermission "exitVM.*"
授予来自类路径的代码),因为通常会在评估权限之前评估此类权限通过政策。 为了拒绝任何这些权限,您必须将ClassLoader
替换为:- 要么不首先授予权限,要么
- 将它加载的类映射到
ProtectionDomain
子类的实例,覆盖implies(Permission)
这样:- 它总是委托政策,或
- 以类似于
DenyingPolicy
的方式处理DenyingPolicy
。
1:有关此类权限的列表,请参阅例如Maass,M。(2016)。 有效应用沙箱的理论与工具。 ,表3.1(第47页)。