因此,经过几个小时的解决方法,目前在Google App Engine上禁用了Reflection的限制,我想知道是否有人可以帮助我理解为什么对象反射会成为一种威胁。是因为我可以检查一个类的私有变量还是有其他更深层次的原因?
答案 0 :(得分:23)
1 - 反思(作为一个概念)确实与安全/保障正交。
java的设计非常注重使其成为一个安全的平台,静态类型,安全管理器,类加载器<的有条理使用/ strong>,无法搞砸指针/ 内存。你可以在Masterminds of programming阅读James Gosling的采访,这很有意思。
但是,更强大的反射能力,你越难以确保事情的安全。反射失败,特别是静态类型,可能导致运行时错误。
但也可能发生更微妙的事情。例如,类加载器 - 可以被认为是系统中的反射钩子 - 在早期版本的Java中没有正确设计,导致潜在的类型替换。 Gilad Bracha撰写的文章Dynamic class loading in the JVM,对这些问题充满洞察力。
不能完全关闭反思;它总是可以反思自己的公共领域/方法。但是,可以禁用对AccessibleObject.setAccessible
的私有结构的反思,因为它会破坏封装。通过访问私人领域等,可以检查和修改内部数据。它可能导致各种恶意攻击,例如
strings
不再是不可变的,可以更改(请参阅此question)最后还有其他机制使安全性处于危险之中,特别是sun.misc.Unsafe
可以直接访问内存 - 指针又回来了。
2 - 现在,问题在于反思(在实践中)是否会导致许多风险。
我已经阅读了@dbyrne指向的链接,但主要是关于.net。此外,我不确切知道Google App的禁用内容。它只是ReflectPermission
或安全管理员的其他许可吗?一个危险显然是访问文件系统并乱七八糟。
在实践中可以讨论访问私有数据和破坏封装的问题。编写安全代码确实非常困难,即使不更改访问修饰符,您也可以以不恰当的方式对类进行子类化 - 除非它们是final
,或者更好,密封 - 并传递它们。这就是defensive copying试图防范的内容。
由于向下传播,类型安全性也受到运行时错误的威胁,所以这一点也可以争论。
在共享/托管环境中,安全性是相对的。在语言级别,您可以例如不阻止模块表单消耗100%的CPU或消耗最多OutOfMemoryException
的所有内存。这些问题需要通过其他方式解决,通常是在操作系统级别,通过虚拟化和配额来解决。
所以我的个人答案是:反射是一种安全风险,但与其他潜在的攻击媒介相比,实际上没有那么大。
答案 1 :(得分:3)
应用程序可以使用Java反射API来访问和更新字段,并执行普通Java访问/可见性规则禁止的方法。有点聪明才智,这足以:
在某些情况下,它甚至可能允许注入恶意本机代码。
答案 2 :(得分:2)
首先,如果您没有安装SecurityManager
,那么您无论如何都不安全。
其次,除非setAccessible()
已启用,否则反射不会打开重大漏洞,并且本身需要进行安全检查(由setAccessChecks
reflection permission管理)。如果没有它,虽然您可能知道私有字段或方法存在(虽然它本身需要accessDeclaredMembers
runtime permission),但您无法对该知识做任何事情。攻击的最佳选择可能是使用序列化对象,但这是一个完整的“蜡球”。
另请注意,编写安全的安全管理器和类加载器并非易事。如果你没有追求超级大师(或者更可能是令人尴尬的失败程度),最好把这些留给别人。
答案 3 :(得分:1)
GAE是一个共享托管环境,托管来自多个用户的WAR文件。很可能多个WAR文件托管在同一个JVM中,因为每个WAR生成一个进程非常荒谬。因此,沙箱每个war文件的唯一方法是通过每个WAR文件的自定义类加载器。
现在,假设允许反射。您could then walk the classloader hierarchy并枚举属于不同用户的WAR文件中的类/方法。显然,这是一个很大的问题。
答案 4 :(得分:0)
我的理论是谷歌试图隐藏某些东西。通过禁用Reflection,Google可以隐藏变量名称,函数调用以及完整的API。如果谷歌隐藏了类似API的东西,那么他们肯定不会告诉你它。
我知道Reflection在安全测试中扮演着非常重要的角色。例如,您可以使用反射自动生成Fuzz测试。 AxMan使用TypeLib标识构成COM对象的所有类及其方法调用。使用此信息,AxMan将实例化每个类,并使用长字符串和大数字的排列调用每个方法。类似的测试由SOAP Fuzzers使用WSDL文件进行反射。