安全管理器与访问控制器
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 SecurityManager
与AccessController
”部分:
回想本章前面在调用安全检查时调用
checkPermission
和调用SecurityManager
类中定义的其他check
方法之间的区别。那时的选择取决于您是否依赖于任何 Java 2 之前的安全管理器类。现在您有另一种选择:调用SecurityManager
中定义的checkPermission
方法或AccessController
中定义的方法。这些方法在两个主要方面有所不同。首先,有时不存在已安装的
SecurityManager
,因此您不能在其上调用check
或checkPermission
方法。相比之下,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 并允许执行任何操作,而“扩展”甚至无法读取系统属性。
【讨论】:
以上是关于安全管理器与访问控制器的主要内容,如果未能解决你的问题,请参考以下文章