在Java策略文件中,grant codeBase
语法指定应授予哪些代码库哪些权限。例如,
grant codeBase“file:/ C:/abc.jar”{ 允许 java.security.AllPermission; };
将AllPermission
授予abc.jar
以类似的方式,是否有办法deny
特定语法的权限?像这样:
拒绝codeBase“file:/ C:/def.jar”{ 允许 java.io.FilePermission中; };
以便def.jar
中的代码获得除FilePermission之外的所有其他权限?
这甚至可能吗?
我知道这可以使用SecurityManager
类轻松完成,但我只是想知道这是否可以通过仅使用策略文件。
答案 0 :(得分:14)
我意识到这已经快一年了,但我想我正在尝试做类似的事情。
有一种方法可以设置运行时权限,以便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;
}
答案 1 :(得分:4)
您可以使用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
更改优先级(默认值为{ {1}} - 保持向后兼容)。
例如,你可以做某事。像:
"deny"
其他例子是here。
答案 2 :(得分:1)
没有。对于策略文件没有这样的实现。如果你真的很绝望,你可以编写自己的系统。
答案 3 :(得分:0)
实现拒绝规则支持的最少参与方法之一是:
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/>
* <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/>
* <em><target_class_name>:<target_name>(:<target_actions>)</em><br/>
* <br/>
* where:
* <ul>
* <li><em><target_class_name></em> is the fully qualified name of the target permission's
* class,</li>
* <li><em><target_name></em> is the {@linkplain #getName() name} of the target
* permission,</li>
* <li><em>(<target_actions>)</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
嵌入普通的 grant 规则中;例如,以下规则将授予所有但 读取系统属性的能力,其名称以“user”开头, to 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());
。
警告:虽然在语义上正确,但在上一个答案的评论中提到,上面的例子是无效的,因为仍然授予危险权限,例如{{1隐式允许沙盒代码执行任何操作,包括SecurityPermission "setPolicy"
禁止的操作。要防止这种情况发生,而不是从DeniedPermission
中减去权限,请考虑从AllPermission
中减去AllSafePermission
,其中AllSafePermission
定义为implies
所有除< / strong>已知沙箱失败权限 1 。
备注强>
(String)
和/或(String, String)
构造函数,并适当地覆盖{ {1}}。implies(Permission)
待拒绝权限的普通权限子类。implies
不会阻止分配给保护域的权限statically(例如默认授予DenyingPolicy
来自类路径的代码)在评估策略维护的权限之前,通常会对这些权限进行评估。为了拒绝任何这些权限,您必须将RuntimePermission "exitVM.*"
替换为:
ClassLoader
子类的实例,覆盖ProtectionDomain
,以便:
implies(Permission)
的方式处理DeniedPermission
。1:有关此类权限的列表,请参阅例如Maass, M. (2016). A Theory and Tools for Applying Sandboxes Effectively.,表3.1(第47页)。