Файл политики Java - Запретить разрешения для кодовой базы - PullRequest
4 голосов
/ 15 февраля 2011

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

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

предоставляет AllPermission для кода внутри abc.jar

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

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

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

Возможно ли это?

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

Ответы [ 4 ]

14 голосов
/ 18 января 2012

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

Существует способ установить разрешения во время выполнения так, чтобы 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;

}
4 голосов
/ 29 января 2014

Вы можете использовать библиотеку 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

или вы можете просто программно заменить реализацию политики в вашем коде:

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.*";
};

Другие примеры здесь .

1 голос
/ 15 февраля 2011

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

0 голосов
/ 30 августа 2017

Один из наименее задействованных подходов к достижению правила отказа поддержки заключается в:

  • Определить «отрицательный» 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.", для некоторых. 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).

...