首页 > 解决方案 > 如何防止仅针对某些领域的反射?

问题描述

我们都知道,java中字段和方法的关键字“private”只在构建时有效,而在运行时需要3行才能绕过。我正在为某些东西制作插件系统,这些插件是在我的进程中加载​​的 jar。所以,我需要一种方法来防止插件访问我游戏的某些字段,这些字段不能从外部访问。问题是“private”关键字没用,Reflection.registerFieldsToFilter 也没用。我试过的:

使字段私有(field.setAccessible() 绕过)

做 Reflection.registerFieldsToFilter (Class.getDeclaredFields0() 绕过)

那么我该怎么做才能使某些字段/方法/类实际上是私有的?

标签: javareflection

解决方案


如果 aSecurityManager不存在,则无法保证将您的字段设为私有。

准确地说,如果SecurityManager撤销以下权限之一,您的字段将无法访问:

  • accessDeclaredMembers: 通过反射提供对类成员的访问
  • suppressAccessChecks: 提供对类的非公共成员的访问

作为参考,https://docs.oracle.com/javase/7/docs/technotes/guides/security/permissions.html

如果你的SecurityManager

  1. 授予上述权限,您可以通过修改过滤器映射getProtectionDomain来调用以保护您的字段。Reflection.registerFieldsToFilter然后,您还可以通过取消过滤java.lang.System.security字段来替换 SecurityManager 并使用反射访问它。但是,这不是一个合适的方法。如果插件将其字段添加到过滤器映射并修改SecurityManager过滤器映射不再可访问,则下一个插件不能重复相同的过程。此外,这违背了安全管理器和访问修饰符的目的。

  2. 授予除 之外的三个提到的权限getProtectionDomain,您不能过滤您的字段,而其他人可以使用反射来访问您的字段。

  3. 不授予accessDeclaredMembersor suppressAccessChecks,那么您的字段可以安全地通过反射访问。

方法一:设置一个SecurityManager

相反,您可以SecurityManager撤销部分/所有上述权限,并将 getter 和 setter 添加到您希望其他插件可以访问的字段。如果你的插件不负责设置合适的SecurityManager,你可以在你的插件的信息页面上做一个通知,提醒用户SecurityManager用其他值得信赖的方法设置。

方法二:混淆和源码封闭

由于反射在序列化中被广泛使用,另一种方法是不要让你的插件开源,并且混淆你的代码,这样开发人员将很难追踪你一直在谈论的领域。

方法 3:使其成为 Web 服务,但其可行性取决于您的插件的功能。

方法4:拒绝模块或包内的反射访问 当包没有修饰符opens时,无法通过模块外的反射访问它,对于没有.的模块也是如此open。您还可以定义to modulename只有该模块可以通过反射访问您的包的位置:

module example {
    opens package.one //can be accessed via reflection
    exports package.two //can only be accessed during compilation i.e. no reflection
}

我写了一篇关于绕过a的文章,SecurityManager上面授予了3个权限,虽然它有点过时了。 https://github.com/Bernard2518141184/Disable-Security-Manager


推荐阅读