安全管理器与访问控制器

Posted

技术标签:

【中文标题】安全管理器与访问控制器【英文标题】:Security Manager vs Access Controller 【发布时间】:2012-11-25 20:12:43 【问题描述】:

我试图阻止玩家的某些操作,但不是我的游戏基础设施,为此我正在使用安全管理器。看起来是这样的

public class GameSecurityManager extends SecurityManager 
@Override
public void checkPackageAccess(String pkg) 
 super.checkPackageAccess(pkg);
 if (isPlayer()) 
  if (pkg.startsWith("ca.hilikus.jrobocom")) 
   if (!"ca.hilikus.jrobocom.player".equals(pkg) && !"ca.hilikus.jrobocom.robot.api".equals(pkg)) 
        throw new SecurityException("No access to game packages");
   


关于安全管理器的文档非常稀少,大部分来自 90 年代。 AccessController 的情况更糟。但是,我确实找到了this, section 6.2 声明的位置

我们鼓励在应用程序代码中使用 AccessController,而自定义安全管理器(通过子类化)应该是最后的手段,并且应该格外小心。

你同意这个说法吗?有人可以解释为什么会这样吗?如果是这样,我将如何完成与我粘贴的示例代码类似的事情?我试图阻止诸如反射、线程化和基于上下文实例化某些对象之类的事情(例如上面的isPlayer())。访问控制 javadoc 讨论的唯一内容是特殊代码块中的特权操作,但 它没有显示如何使用控制器来实际阻止操作

【问题讨论】:

【参考方案1】:

引用本书Inside Java 2 Platform Security的“6.4.9 SecurityManagerAccessController”部分:

回想本章前面在调用安全检查时调用checkPermission 和调用SecurityManager 类中定义的其他check 方法之间的区别。那时的选择取决于您是否依赖于任何 Java 2 之前的安全管理器类。现在您有另一种选择:调用SecurityManager 中定义的checkPermission 方法或AccessController 中定义的方法。这些方法在两个主要方面有所不同。

首先,有时不存在已安装的SecurityManager,因此您不能在其上调用checkcheckPermission 方法。相比之下,AccessController 中的静态方法始终可供调用。回想一下调用SecurityManager的成语:

SecurityManager sm = System.getSecurityManager();
if (sm != null)
    sm.checkPermission(permission);

但你可以随时调用

AccessController.checkPermission(permission);

因此,无论是否安装了系统范围的SecurityManager,如果您想确保始终调用您的安全检查,您应该调用AccessController。但是请注意,一些现有应用程序会测试是否安装了SecurityManager 的实例。然后,根据该测试的结果(表示一种或其他安全状态),这些应用程序会采取不同的行动。对于这些应用程序的向后兼容性,调用SecurityManager 更为合适。

第二个区别是调用SecurityManager并不能保证特定的访问控制算法;有人可能已经扩展它并安装了自定义安全管理器。相比之下,调用AccessController 保证使用前面指定的完整访问控制算法。因此,如果您不想将安全检查委托给自定义安全管理器,则应直接调用 AccessController。否则,请致电SecurityManager

另外,请注意,由于SecurityManager 类定义了一个用于安全检查的通用接口,它不提供AccessController 定义的特权机制。事实上,如果您在代码中使用了特权机制,但后来调用SecurityManager 进行安全检查,如果您安装的安全管理器不是 Java 2 提供的,并且没有请咨询AccessController 或同等机构。

您可能想知道我们为什么提供这些选择。一种做事方式还不够好吗?这些选择基于经验。需要在通用性和一致性之间进行平衡权衡。从长远来看,我们预计不会经常需要自定义安全管理器,并且即使定义了它们,它们也将基于 AccessController 中的现有功能构建。特别是,它们将提供额外的功能,而不是促进不兼容的行为。然而,在一个必须强制执行完全不同类型的安全策略的特殊环境中,可以想象,定制的安全管理器可能无法使用AccessController 实现的算法。

您还可以查看 Oracle 的 Java 平台标准版 安全开发人员指南中的 SecurityManager versus AccessController 部分。

【讨论】:

【参考方案2】:

您不需要编写自己的SecurityManager 或AccessController,您需要的是自定义Permission。在你写完一个之后,你只需要启动一个 SecurityManager 并在你想要保护的每个方法中进行安全检查!您可能需要执行特权操作以避免过多的检查传播。 :)

【讨论】:

我要保护的方法不是我的方法。它们是 JDK 方法,如反射,或创建新的类加载器。我该如何使用自定义权限?? 我不知道我是否正确,您编写了一个 java 库(游戏),将分发给人们扩展它并玩(编写玩家代码)或者您只是有一个游戏你想禁止有人篡改它吗? 前者。所以我试图阻止其他一些不是由我实现而是由 JDK 实现的操作 那么就会出现问题:( 因为有两种启用 SecurityManager 的方法:通过 jvm 选项或从您的代码中以编程方式启用,但只能运行 SecurtyManager 的一个实例,因此有人可以覆盖您的设置。我建议您查找其他保护选项,例如代码混淆或使用在线状态存储的加密。【参考方案3】:

(为了未来用户的利益)

对此的答案是您应该为应用程序提供安全策略。如果这无法控制,那你就完全不走运了。

在策略中,您将授予对“托管扩展”的某些合适子集的访问权限,而您的“游戏包”将被授予 AllPermissions。然后,您为您的库创建权限并授予对“托管扩展”的适当访问权限。

然后在您的 API 中,您会执行以下操作;

public String someMethod( String someArg )

    if( System.getSecurityManager() == null )
        return internalSomeMethod( someArg );
    MyPermission required = new MyPermission( "whatever" );
    AccessController.checkPermission( required );
    return AccessController.doPrivileged(new PrivilegedAction<String>()
    
        public String run()
        
            return internalSomeMethod( somArg );
        
     );

private String someInternalMethod( String someArg )...

因此,即使“托管扩展”只有“MyPermission”,游戏引擎也可以拥有 AllPermissions 并允许执行任何操作,而“扩展”甚至无法读取系统属性。

【讨论】:

以上是关于安全管理器与访问控制器的主要内容,如果未能解决你的问题,请参考以下文章

云原生训练营模块七 Kubernetes 控制平面组件:调度器与控制器

将 narayana 事务管理器与休眠集成

配置管理器与网络设置

Android 工作管理器与服务?

JAVA布局管理器与面板组合

Python上下文管理器与with语句