Файл политики Java - Запретить разрешения для кодовой базы

В файле политики Java grant codeBase синтаксис определяет, какая кодовая база должна быть предоставлена, какие разрешения. например,

предоставить codeBase "file:/C:/abc.jar" {разрешение java.security.AllPermission; };

гранты AllPermission кодировать внутри abc.jar

Аналогичным образом, есть ли способ deny разрешения на определенный синтаксис? Как это:

отказать в codeBase "file:/C:/def.jar" {разрешение java.io.FilePermission; };

так что код внутри def.jar получает все остальные разрешения, кроме FilePermission?

Это вообще возможно?

Я знаю, что это легко сделать, используя SecurityManager класс, но я просто хочу знать, возможно ли это, используя только файл политики.

4 ответа

Решение

Нет. Ничего подобного не реализовано для файлов политики. Вы могли бы написать свою собственную систему, если бы вы действительно были в отчаянии.

Я понимаю, что это почти год спустя, но я думаю, что пытаюсь сделать что-то подобное.

Существует способ установить разрешения во время выполнения так, чтобы Java не предоставляла глобальные разрешения. Затем вы можете указать только те разрешения, которые вы хотите предоставить вашему приложению. Ключ должен запустить ваше приложение с опциями ниже.

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

Обратите внимание на двойные равные -Djava.security.policy==policyFile.txt, Двойное равенство == означает использовать только разрешения в именованном файле, а не один знак равенства -Djava.security.policy=policyFile.txt что означает использование этих разрешений в дополнение к унаследованным глобальным разрешениям.

Затем создайте файл политики, исключая разрешения, которые вы хотите запретить:

// 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-зависимость в ваше приложение

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

А затем включите его для своего приложения, используя стандартные системные свойства:

-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 (значение по умолчанию "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.
 * <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;
    }

}

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();
    }

}

использование

Просто вставлять DeniedPermission в пределах простых старых правил предоставления грантов; например, следующее правило предоставит всем, кроме возможности чтения свойств системы с именем, начинающимся с "user.", классы 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";
};

Затем установите DenyingPolicy с помощью Policy.setPolicy(new DenyingPolicy());,

Предостережение: хотя семантически правильно, как было упомянуто в комментарии предыдущего ответа, приведенный выше пример неэффективен, так как он все еще предоставляет опасные разрешения, такие как SecurityPermission "setPolicy" которые неявно позволяют коду с песочницей делать все, что пожелает, включая действия, запрещенные DeniedPermission, Чтобы этого не произошло, вместо того чтобы вычитать разрешения из AllPermission рассмотрим вычитание из AllSafePermission вместо этого, где AllSafePermission определяется так, что это implies все, кроме известных разрешений для песочницы 1.

Заметки

  • Любое разрешение может быть заключено в запрещенное разрешение, если оно соответствует стандартному целевому соглашению имя-действие (действия), выставляет (String) и / или (String, String) конструктор и соответственно переопределяет implies(Permission),
  • Чтобы отказать в нескольких разрешениях одновременно:
    • Создайте обычный подкласс разрешений, который implies разрешения для отказа в доступе.
    • "Предоставьте" запрещенное разрешение, в свою очередь ссылаясь на экземпляр вашей реализации, из конфигурации политики.
  • DenyingPolicy не запрещает разрешения, статически назначаемые домену защиты (например, RuntimePermission "exitVM.*" предоставляется по умолчанию коду, исходящему из пути к классам) от предоставления, поскольку, как правило, оценка таких разрешений происходит до оценки разрешений, поддерживаемых политикой. Для того чтобы отрицать любое из этих разрешений, вам придется заменить ClassLoader с тем, что:
    • либо не предоставляет разрешения в первую очередь, либо
    • отображает классы, которые он загружает в экземпляры ProtectionDomain подкласс, который переопределяет implies(Permission) такой что:
      • он всегда делегирует политике, или
      • процессы DeniedPermission схожим образом DenyingPolicy,

1: Список таких разрешений см., Например, Maass, M. (2016). Теория и инструменты для эффективного применения песочниц. , таблица 3.1 (стр. 47).

Другие вопросы по тегам