Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用AccessController.doPrivileged()限制权限并不总是按预期工作_Java_Permissions_Sandbox_Securitymanager_Accesscontrolexception - Fatal编程技术网

Java 使用AccessController.doPrivileged()限制权限并不总是按预期工作

Java 使用AccessController.doPrivileged()限制权限并不总是按预期工作,java,permissions,sandbox,securitymanager,accesscontrolexception,Java,Permissions,Sandbox,Securitymanager,Accesscontrolexception,我用以下代码建立了一种“Java沙盒”: // #1 new File("xxx").exists(); // #2 PrivilegedExceptionAction<Boolean> untrusted = () -> new File("xxx").exists(); untrusted.run(); // #3 Policy.setPolicy(new Policy() { @Override

我用以下代码建立了一种“Java沙盒”:

    // #1
    new File("xxx").exists();

    // #2
    PrivilegedExceptionAction<Boolean> untrusted = () -> new File("xxx").exists();
    untrusted.run();

    // #3
    Policy.setPolicy(new Policy() {
        @Override public boolean implies(ProtectionDomain domain, Permission permission) { return true; }
    });
    System.setSecurityManager(new SecurityManager());

    AccessControlContext noPermissionsAccessControlContext;
    {
        Permissions noPermissions = new Permissions();
        noPermissions.setReadOnly();

        noPermissionsAccessControlContext = new AccessControlContext(
            new ProtectionDomain[] { new ProtectionDomain(null, noPermissions) }
        );
    }

    AccessControlContext allPermissionsAccessControlContext;
    {
        Permissions allPermissions = new Permissions();
        allPermissions.add(new AllPermission());
        allPermissions.setReadOnly();

        allPermissionsAccessControlContext = new AccessControlContext(
            new ProtectionDomain[] { new ProtectionDomain(null, allPermissions) }
        );
    }

    // #4
    try {
        AccessController.doPrivileged(untrusted, noPermissionsAccessControlContext);
        throw new AssertionError("AccessControlException expected");
    } catch (AccessControlException ace) {
        ;
    }

    // #5
    PrivilegedExceptionAction<Boolean> evil = () -> {
        return AccessController.doPrivileged(untrusted, allPermissionsAccessControlContext);
    };
    try {
        AccessController.doPrivileged(evil, noPermissionsAccessControlContext);
        throw new AssertionError("AccessControlException expected"); // Line #69
    } catch (AccessControlException ace) {
        ;
    }
根据我在JRE JAVADOC中读到的内容

doPrivileged
public static <T> T doPrivileged(PrivilegedExceptionAction<T> action, AccessControlContext context)
     throws PrivilegedActionException

Performs the specified PrivilegedExceptionAction with privileges enabled and restricted by the
specified AccessControlContext. The action is performed with the intersection of the the permissions
possessed by the caller's protection domain, and those possessed by the domains represented by the
specified AccessControlContext.

If the action's run method throws an unchecked exception, it will propagate through this method.

Parameters:
    action -  the action to be performed
    context - an access control context representing the restriction to be applied to the caller's
              domain's privileges before performing the specified action. If the context is null,
              then no additional restriction is applied.
Returns:
    the value returned by the action's run method
Throws:
    PrivilegedActionException - if the specified action's run method threw a checked exception
    NullPointerException      - if the action is null
See Also:
    doPrivileged(PrivilegedAction), doPrivileged(PrivilegedExceptionAction,AccessControlContext)
doPrivileged
公共静态T-doPrivileged(PrivilegedExceptionAction操作,AccessControlContext上下文)
抛出PrivilegedActionException
执行指定的PrivilegedExceptionAction,其权限由
指定的AccessControlContext。该操作是在权限的交集处执行的
由调用方的保护域拥有,以及由
指定的AccessControlContext。
如果操作的run方法抛出未检查的异常,它将通过此方法传播。
参数:
动作-要执行的动作
context—一个访问控制上下文,表示要应用于调用方的
在执行指定操作之前,域的权限。如果上下文为空,
那么就没有附加的限制了。
返回:
操作的run方法返回的值
抛出:
PrivilegedActionException-如果指定操作的run方法引发选中的异常
NullPointerException-如果操作为null
另见:
DoPrivilegedAction(PrivilegedAction)、DoPrivilegedExceptionAction(PrivilegedExceptionAction、AccessControlContext)
,我希望不受信任的代码将在没有权限的情况下执行,从而抛出一个
AccessControlException
,但这不会发生


为什么??我能做些什么来修补这个安全漏洞呢?

好吧,不受信任的代码最初是在没有权限的情况下执行的。。。直到它请求恢复其权限(嵌套
doPrivileged
调用
AllPermission
AccessControlContext
)。这个请求得到了尊重,因为根据你的
政策
,你的所有代码,包括“邪恶”行为,都是完全有特权的。换句话说,
doPrivileged
不是“按需沙箱工具”。它仅可用作其直接调用方在策略决策点(ClassLoader+
SecurityManager
/
策略
)已授予的权限范围内限制或增加其权限的一种手段。如果有权的话,电话线下游的呼叫者完全可以“恢复”该更改——再次根据策略决策点,而不是之前任何呼叫者的意见。因此,这是预期行为,而不是安全漏洞

有什么解决办法

首先,使用基础设施肯定有一种“规范的”/明智的方法。根据该最佳实践,通过打包和类加载器将受信任代码与不受信任代码隔离,从而使两者与可单独授权的不同域相关联。如果不受信任的代码只被授予(比如)从特定文件系统目录读取的权限,那么再多的
doPrivileged
调用都不会使它能够(比如)打开URL连接

除此之外,我们当然可以想出一百零二个备选方案,创造性地(但不一定是安全地)利用基础设施的不同移动部分,使其发挥优势

例如,我建议使用一个带有本地线程的自定义保护域来大致完成您想要的任务,即在执行不受信任的操作的整个过程中按需对一个通常具有特权的域进行沙箱处理


另一种在单个保护域内选择性地对代码进行沙箱处理的方法是建立默认黑名单,并使用
DomainCombiner
s将可信的执行路径列入白名单。请注意,它仅适用于以编程方式设置
SecurityManager
的情况

首先,需要确保默认情况下不授予任何权限,无论是通过
ClassLoader
1还是通过
Policy
2

然后获得一个“特殊的”
AccessControlContext
,它耦合到一个域合并器,该域合并器无条件地产生
AllPermission
,如下所示:

// this PD stack is equivalent to AllPermission
ProtectionDomain[] empty = new ProtectionDomain[0];

// this combiner, if bound to an ACC, will unconditionally
// cause it to evaluate to AllPermission
DomainCombiner combiner = (current, assigned) -> empty;

// bind combiner to an ACC (doesn't matter which one, since
// combiner stateless); note that this call will fail under
// a security manager (will check SecurityPermission
// "createAccessControlContext")
AccessControlContext wrapper = new AccessControlContext(
    AccessController.getContext(), combiner);

// bind wrapper and thus combiner to current ACC; this will
// anew trigger a security check under a security manager.
// if this call succeeds, the returned ACC will have been
// marked "authorized" by the runtime, and can thus be
// reused to elevate permissions "on-demand" in the future
// without further a priori security checks.
AccessControlContext whitelisted = AccessController.doPrivileged(
    (PrivilegedAction<AccessControlContext>) AccessController::getContext,
    wrapper);
//此PD堆栈相当于AllPermission
ProtectionDomain[]为空=新的ProtectionDomain[0];
//如果绑定到ACC,则该组合器将无条件地
//使其计算为AllPermission
域合并器合并器=(当前,已分配)->空;
//将组合器绑定到ACC(不管是哪一个,因为
//组合器(无状态);请注意,此调用将在以下情况下失败:
//安全经理(将检查SecurityPermission
//“createAccessControlContext”)
AccessControlContext包装器=新的AccessControlContext(
AccessController.getContext(),合并器);
//将包装器和合路器绑定到当前ACC;这将
//在安全管理器下重新触发安全检查。
//如果此调用成功,则返回的ACC将被删除
//由运行时标记为“authorized”,因此可以
//重用以在将来“按需”提升权限
//没有进一步的先验安全检查。
AccessControlContext白名单=AccessController.doPrivileged(
(PrivilegedAction)AccessController::getContext,
包装纸);
现在可以建立一个标准的安全管理器来强制执行默认的黑名单。从这一点开始,所有代码都将被列入黑名单——除了引用“白名单”/“后门”ACC的代码之外,它可以利用这些代码逃离沙箱:

PrivilegedAction<Void> action = () -> {
    System.getSecurityManager().checkPermission(new AllPermission());
    return null;
};

// this will succeed, strange as it might appear
AccessController.doPrivileged(action, whitelisted);
// this won't
AccessController.doPrivileged(action);
// neither will this
action.run();
PrivilegedAction=()->{
System.getSecurityManager().checkPermission(新建AllPermission());
返回null;
};
//这将成功,尽管看起来很奇怪
AccessController.doPrivileged(操作,白名单);
//这不会
AccessController.doPrivileged(操作);
//这也不会
action.run();
这为灵活性留下了相当大的空间。您可以直接调用“白名单”中的其他受信任代码
PrivilegedAction<Void> action = () -> {
    System.getSecurityManager().checkPermission(new AllPermission());
    return null;
};

// this will succeed, strange as it might appear
AccessController.doPrivileged(action, whitelisted);
// this won't
AccessController.doPrivileged(action);
// neither will this
action.run();