Java 策略文件 - 拒绝对代码库的权限

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5003565/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 09:01:05  来源:igfitidea点击:

Java Policy file - Deny permissions to a codebase

javasecuritymanagerpolicyfiles

提问by securitypolicymanager

In the Java policy file, the grant codeBasesyntax specifies which codebase should be granted which permissions. for example,

在 Java 策略文件中,grant codeBase语法指定应授予哪个代码库哪些权限。例如,

grant codeBase "file:/C:/abc.jar" { permission java.security.AllPermission; };

授予 codeBase "file:/C:/abc.jar" { 权限 java.security.AllPermission; };

grants AllPermissionto code inside abc.jar

授予AllPermissionabc.jar 中的代码

In a similar way, Is there a way to denypermissions to a specific syntax? Like this:

以类似的方式,有没有办法deny获得特定语法的权限?像这样:

deny codeBase "file:/C:/def.jar" { permission java.io.FilePermission; };

拒绝 codeBase "file:/C:/def.jar" { 权限 java.io.FilePermission; };

so that the code inside def.jargets every other permissions except the FilePermission?

以便里面的代码def.jar获得除 FilePermission 之外的所有其他权限?

Is this even possible?

这甚至可能吗?

I know this can be easily done using the SecurityManagerclass, but I just want to know if this is possible by using the policy file only.

我知道这可以使用SecurityManager类轻松完成,但我只想知道这是否可以仅使用策略文件。

采纳答案by Tom Hawtin - tackline

No. There is nothing like this implemented for policy files. You could write your own system, if you were really desperate.

不。没有为策略文件实现类似的东西。如果您真的很绝望,您可以编写自己的系统。

回答by pinkonion

I realize this is almost a year late but I think I am trying to do something similar.

我意识到这几乎晚了一年,但我想我正在尝试做类似的事情。

There is a way to set the runtime permissions such that Java won't grant the global permissions. Then you can specify only the permissions you want granted for your app. The key is to run your app with the options below.

有一种方法可以设置运行时权限,这样 Java 就不会授予全局权限。然后,您可以仅指定要为应用授予的权限。关键是使用以下选项运行您的应用程序。

java -Djava.security.manager -Djava.security.policy==policyFile.txt MyClass

Note the double equals -Djava.security.policy==policyFile.txt. The double equals ==means to use onlythe permissions in the named file as opposed to the single equal sign -Djava.security.policy=policyFile.txtwhich means use these permissions in addition to the inherited global permissions.

注意双等于-Djava.security.policy==policyFile.txt。双等号==意味着使用命名文件中的权限,而不是单等号-Djava.security.policy=policyFile.txt,这意味着除了继承的全局权限之外还使用这些权限。

Then create a policy file excluding the permissions you want to deny:

然后创建一个策略文件,排除您要拒绝的权限:

// 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;

}

回答by kwart

You can use Progradelibrary, which implements policy file with deny rules.

您可以使用Prograde库,它使用拒绝规则实现策略文件。

Add following Maven dependency to your app

将以下 Maven 依赖项添加到您的应用程序

<dependency>
    <groupId>net.sourceforge.pro-grade</groupId>
    <artifactId>pro-grade</artifactId>
    <version>1.0</version>
</dependency>

And then enable it for your application by using standard system properties:

然后使用标准系统属性为您的应用程序启用它:

-Djava.security.manager=net.sourceforge.prograde.sm.ProgradeSecurityManager -Djava.security.policy==/path/to/your/application.policy

or you can just replace programatically the Policy implementation in your code:

或者您可以以编程方式替换代码中的 Policy 实现:

System.setProperty("java.security.policy","/path/to/your/application.policy");
Policy.setPolicy(new ProgradePolicyFile());

The syntax of policy file stays similar to the standard implementation, but you can use denyinstead of grantand you can also change priorities by using keyword priority(default value is "deny"- to stay backward compatible).

策略文件的语法与标准实现类似,但您可以使用deny代替,grant也可以使用关键字更改优先级priority(默认值为"deny"- 以保持向后兼容)。

For instance, you can do sth. like:

例如,你可以做某事。喜欢:

grant {
    permission java.lang.RuntimePermission "*";
};

deny {
    permission java.lang.RuntimePermission "exitVM.*";
};

Other examples are here.

其他例子在这里

回答by Uux

One of the least involved approaches towards attaining deny rulesupport, is to:

获得拒绝规则支持的最少参与方法之一是:

  • Define a "negative" Permissionsubclass that wraps a regular positive permission and negates it; and
  • wrap the default Policysuch that it (its wrapper) understands such permissions.
  • 定义一个“否定”Permission子类,它包装一个常规的肯定权限并否定它;和
  • 包装默认值Policy,使其(其包装器)理解此类权限。

The DeniedPermissionclass

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.
 * <p>
 * A <code>DeniedPermission</code>, when "granted" to some <code>ProtectionDomain</code>, represents
 * a privilege which <em>cannot</em> be exercised, regardless of any positive permissions
 * (<code>AllPermission</code> included) possessed. In other words, if a set of granted permissions,
 * <em>P</em>, contains a permission of this class, <em>D</em>, then the set of effectively granted
 * permissions is<br/>
 * <br/>
 * &nbsp;&nbsp;&nbsp;&nbsp;<em>{ P<sub>implied</sub> - D<sub>implied</sub> }</em>.
 * </p>
 * <p>
 * Each instance of this class encapsulates a <em>target permission</em>, representing the
 * "positive" permission being negated.
 * </p>
 * Denied permissions employ the following naming scheme:<br/>
 * <br/>
 * &nbsp;&nbsp;&nbsp;&nbsp;<em>&lt;target_class_name&gt;:&lt;target_name&gt;(:&lt;target_actions&gt;)</em><br/>
 * <br/>
 * where:
 * <ul>
 * <li><em>&lt;target_class_name&gt;</em> is the fully qualified name of the target permission's
 * class,</li>
 * <li><em>&lt;target_name&gt;</em> is the {@linkplain #getName() name} of the target
 * permission,</li>
 * <li><em>(&lt;target_actions&gt;)</em> is, optionally, the {@linkplain #getActions() actions
 * string} of the target permission, and</li>
 * <li>the <em>':'</em> character stands for itself.</li>
 * </ul>
 * A denied permission, having a target permission <em>t</em>, is said to
 * {@linkplain #implies(Permission) <em>imply</em>} another permission <em>p</em>, iff:
 * <ul>
 * <li>p <em>is not</em> itself a denied permission, and <code>(t.implies(p) == true)</code>,
 * or</li>
 * <li>p <em>is</em> a denied permission, with a target <em>t1</em>, and
 * <code>(t.implies(t1) == true)</code>.</li>
 * </ul>
 * <p>
 * It is the responsibility of the policy decision point (e.g., the <code>Policy</code> provider) to
 * take denied permission semantics into account when issuing authorization statements.
 * </p>
 */
public final class DeniedPermission extends BasicPermission {

    private static final String NULL_STR_ARG = "<null>", EMPTY_STR_ARG = "<empty> ";
    private static final long serialVersionUID = 2102974454790623344L;

    private final Permission target;

    /**
     * Instantiates a <code>DeniedPermission</code> that encapsulates a target permission of the
     * indicated class, specified name and, optionally, actions.
     * 
     * @throws IllegalArgumentException
     *             if:
     *             <ul>
     *             <li><code>targetClassName</code> is <code>null</code>, the empty string, does not
     *             refer to a concrete <code>Permission</code> descendant, or refers to
     *             <code>DeniedPermission.class</code> or <code>UnresolvedPermission.class</code>.</li>
     *             <li><code>targetName</code> is <code>null</code>.</li>
     *             <li><code>targetClassName</code> cannot be instantiated, and it's the caller's fault;
     *             e.g., because <code>targetName</code> and/or <code>targetActions</code> do not adhere
     *             to the naming constraints of the target class; or due to the target class not
     *             exposing a <code>(String name)</code>, or <code>(String name, String actions)</code>
     *             constructor, depending on whether <code>targetActions</code> is <code>null</code> or
     *             not.</li>
     *             </ul>
     * @throws SecurityException
     *             if a <code>SecurityManager</code>, <code>sm</code>, is installed, and the invocation
     *             <code>sm.checkPackageAccess(targetClassPackageName)</code> (where
     *             <code>targetClassPackageName</code> is the package of the class referred to
     *             by <code>targetClassName</code>) 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 <code>DeniedPermission</code> that encapsulates the given target permission.
     * 
     * @throws IllegalArgumentException
     *             if <code>target</code> is <code>null</code>, a <code>DeniedPermission</code>, or an
     *             <code>UnresolvedPermission</code>.
     */
    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 <code>DeniedPermission</code> that encapsulates a target permission of the class,
     * name and, optionally, actions, collectively provided as the <code>name</code> argument.
     * 
     * @throws IllegalArgumentException
     *             if:
     *             <ul>
     *             <li><code>name</code>'s target permission class name component is empty, does not
     *             refer to a concrete <code>Permission</code> descendant, or refers to
     *             <code>DeniedPermission.class</code> or <code>UnresolvedPermission.class</code>.</li>
     *             <li><code>name</code>'s target name component is <code>empty</code></li>
     *             <li>the target permission class cannot be instantiated, and it's the caller's fault;
     *             e.g., because <code>name</code>'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 <code>(String name)</code>, or
     *             <code>(String name, String actions)</code> constructor, depending on whether the
     *             target actions component is empty or not.</li>
     *             </ul>
     * @throws SecurityException
     *             if a <code>SecurityManager</code>, <code>sm</code>, is installed, and the invocation
     *             <code>sm.checkPackageAccess(targetClassPackageName)</code>
     *             (where <code>targetClassPackageName</code> is the package of the class referred to
     *             by <code>name</code>'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;
    }

}

The DenyingPolicyclass

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 <code>Policy</code>.
 */
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<ProtectionDomain>) 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 <code>true</code> iff:
     *         <ul>
     *         <li><code>permission</code> <em>is not</em> an instance of
     *         <code>DeniedPermission</code>,</li>
     *         <li>an <code>implies(domain, permission)</code> invocation on the system-default
     *         <code>Policy</code> yields <code>true</code>, and</li>
     *         <li><code>permission</code> <em>is not</em> implied by any <code>DeniedPermission</code>s
     *         having potentially been assigned to <code>domain</code>.</li>
     *         </ul>
     */
    @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> 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<Permission>) () -> 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();
    }

}

Usage

用法

Just embed DeniedPermissions within plain old grantrules; for instance, the following rule will grant everything butthe ability to readSystem Properties with a name starting with "user.", to some.jar's classes.

只需将DeniedPermissions嵌入到普通的旧授权规则中;例如,下面的规则将给予一切,但在能力阅读与开头的名称系统属性“用户”,以some.jar的类。

grant codeBase "file:/home/your_user/classpath/some.jar" {
    permission java.security.AllPermission;
    permission com.example.q5003565.DeniedPermission "java.util.PropertyPermission:user.*:read";
};

Then install a DenyingPolicyvia Policy.setPolicy(new DenyingPolicy());.

然后安装一个DenyingPolicyvia Policy.setPolicy(new DenyingPolicy());

Caveat:While semantically correct, as was mentioned in a previous answer's comment, the above example is ineffective, as it stillgrants dangerous permissions, such as SecurityPermission "setPolicy", which implicitly allow sandboxed code to do whatever it pleases, including the action prohibited by the DeniedPermission. To prevent this from occurring, rather than subtracting permissions from AllPermission, consider subtracting from an AllSafePermissioninstead, where AllSafePermissionis defined such that it implieseverything exceptknown sandbox-defeating permissions1.

警告:虽然语义上是正确的,正如在前面的答案的评论中提到的,上面的例子是无效的,因为它仍然授予危险的权限,例如SecurityPermission "setPolicy",它隐含地允许沙盒代码做任何它想做的事情,包括DeniedPermission. 为了防止发生这种情况,而不是从 中减去权限,而是AllPermission考虑从 中减去AllSafePermission, whereAllSafePermission定义为除了已知的沙盒破坏权限1之外的implies所有内容。

Notes

笔记

  • Any permission can be wrapped by a denied permission, as long as it follows the standard target name-action(s) convention, exposes a (String)and/or (String, String)constructor, and appropriately overrides implies(Permission).
  • To deny multiple permissions at once:
    • Create an ordinary permission subclass that impliesthe to-be-denied permissions.
    • "Grant" a denied permission, in turn referencing an instance of your implementation, from the policy configuration.
  • The DenyingPolicydoes notprevent permissions staticallyassigned to a protection domain (such as RuntimePermission "exitVM.*"granted by default to code originating from the classpath) from being granted, as, generally, evaluation of such permissions occurs prior to evaluation of permissions maintained by the policy. In order to deny any of these permissions as well, you will have to replace the ClassLoaderwith one that:
    • does either not grant the permissions in the first place, or
    • mapsclasses it loads to instances of a ProtectionDomainsubclass, that overrides implies(Permission)such that:
      • it always delegates to policy, or
      • processes DeniedPermissions in a manner similar to DenyingPolicy.
  • 任何权限都可以被拒绝的权限包裹,只要它遵循标准的目标名称-操作约定,公开 a(String)和/或(String, String)构造函数,并适当地覆盖implies(Permission).
  • 一次拒绝多个权限:
    • 创建一个普通权限子类,implies表示要拒绝的权限。
    • 从策略配置中“授予”被拒绝的权限,进而引用您的实现实例。
  • DenyingPolicy不会阻止静态分配给保护域的权限(例如RuntimePermission "exitVM.*"默认授予源自类路径的代码),因为通常情况下,此类权限的评估发生在策略维护的权限的评估之前。为了拒绝这些权限中的任何一个,您必须将其替换为ClassLoader
    • 要么一开始就没有授予权限,要么
    • 它加载的ProtectionDomain映射到子类的实例,该子类覆盖implies(Permission)如下:
      • 它总是委托给政策,或者
      • DeniedPermission以类似于 的方式处理s DenyingPolicy


1: For a listing of such permissions see e.g. Maass, M. (2016). A Theory and Tools for Applying Sandboxes Effectively., table 3.1 (page 47).

1:有关此类权限的列表,请参见Maass, M. (2016)。有效应用沙箱的理论和工具。,表 3.1(第 47 页)。