如何防止仅对某些字段进行反射?
How to prevent reflection only for some fields?
我们都知道java中字段和方法的关键字“private”只在构建时起作用,而在运行时需要3行才能绕过。
我正在为某些东西制作一个插件系统,这些插件是在我的进程中加载的 jar。所以,我需要一种方法来防止插件访问我游戏的某些字段,这些字段不能从外部访问。问题是“private”关键字没用,Reflection.registerFieldsToFilter 也没用。
我尝试过的:
making the field private (field.setAccessible() bypasses)
doing Reflection.registerFieldsToFilter (Class.getDeclaredFields0() bypasses)
那我该怎么做才能让一些 fields/methods/classes 真正私有化?
如果 SecurityManager
不存在,则无法保证将您的字段设为私有。
准确地说,如果SecurityManager
撤销一个以下权限,则您的字段是安全的:
accessDeclaredMembers
:通过反射 提供对class成员的访问
suppressAccessChecks
:提供对 class 的非 public 成员的访问
供参考,https://docs.oracle.com/javase/7/docs/technotes/guides/security/permissions.html
如果你的SecurityManager
授予上述权限和getProtectionDomain
,您可以调用Reflection.registerFieldsToFilter
通过修改过滤器映射来保护您的字段。然后,您还可以通过取消过滤 java.lang.System.security
字段并使用反射访问它来替换 SecurityManager。但是,这不是一种合适的方法。如果一个插件将其字段添加到过滤器映射并修改 SecurityManager
使得过滤器映射不再可访问,则下一个插件不能重复相同的过程。此外,这违背了安全管理器和访问修饰符的目的。
授予除getProtectionDomain
之外的上述三个权限,您不能过滤您的字段,而其他人可以使用反射访问您的字段。
不授予 accessDeclaredMembers
或 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
}
我写了一篇绕过SecurityManager
的文章,上面授予了3个权限,虽然有点过时了。 https://github.com/Bernard2518141184/Disable-Security-Manager
我们都知道java中字段和方法的关键字“private”只在构建时起作用,而在运行时需要3行才能绕过。 我正在为某些东西制作一个插件系统,这些插件是在我的进程中加载的 jar。所以,我需要一种方法来防止插件访问我游戏的某些字段,这些字段不能从外部访问。问题是“private”关键字没用,Reflection.registerFieldsToFilter 也没用。 我尝试过的:
making the field private (field.setAccessible() bypasses)
doing Reflection.registerFieldsToFilter (Class.getDeclaredFields0() bypasses)
那我该怎么做才能让一些 fields/methods/classes 真正私有化?
如果 SecurityManager
不存在,则无法保证将您的字段设为私有。
准确地说,如果SecurityManager
撤销一个以下权限,则您的字段是安全的:
accessDeclaredMembers
:通过反射 提供对class成员的访问
suppressAccessChecks
:提供对 class 的非 public 成员的访问
供参考,https://docs.oracle.com/javase/7/docs/technotes/guides/security/permissions.html
如果你的SecurityManager
授予上述权限和
getProtectionDomain
,您可以调用Reflection.registerFieldsToFilter
通过修改过滤器映射来保护您的字段。然后,您还可以通过取消过滤java.lang.System.security
字段并使用反射访问它来替换 SecurityManager。但是,这不是一种合适的方法。如果一个插件将其字段添加到过滤器映射并修改SecurityManager
使得过滤器映射不再可访问,则下一个插件不能重复相同的过程。此外,这违背了安全管理器和访问修饰符的目的。授予除
getProtectionDomain
之外的上述三个权限,您不能过滤您的字段,而其他人可以使用反射访问您的字段。不授予
accessDeclaredMembers
或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
}
我写了一篇绕过SecurityManager
的文章,上面授予了3个权限,虽然有点过时了。 https://github.com/Bernard2518141184/Disable-Security-Manager