如果我的代码不对反序列化对象的状态或类做任何假设,反序列化不受信任的数据是否安全,或者仅仅反序列化的行为是否会导致意外操作?
(威胁模型:攻击者可以随意修改序列化数据,但也仅此而已)
最佳答案
反序列化本身可能已经不安全了。可序列化类可以定义一个 readObject
方法(另请参阅 specification ),当此类的对象将从流中反序列化时调用该方法。攻击者无法提供此代码,但使用精心设计的输入,她可以使用任何输入调用您类路径上的任何此类 readObject
方法。
代码注入(inject)
有可能制作一个readObject
实现,为任意字节码注入(inject)打开大门。只需从流中读取字节数组并将其传递给 ClassLoader.defineClass
和 ClassLoader.resolveClass()
(请参阅 the former 和 the later 的 javadoc)。我不知道这样的实现有什么用,但这是可能的。
内存耗尽
编写安全的 readObject
方法很困难。直到 somewhat recently HashMap
的 readObject
方法包含以下行。
int numBuckets = s.readInt();
table = new Entry[numBuckets];
这使得攻击者很容易用几十个字节的序列化数据分配几千兆字节的内存,这将使您的系统立即因 OutOfMemoryError
而崩溃。
current implementation Hashtable
似乎仍然容易受到类似的攻击;它根据元素的数量和加载因子计算分配的数组的大小,但是对于 loadFactor
中的不合理值没有任何保护措施,因此我们可以轻松地请求为分配十亿个插槽表中的每个元素。
CPU 负载过高
修复 HashMap
中的漏洞是作为更改的一部分完成的,以解决与基于哈希的映射相关的另一个安全问题。 CVE-2012-2739描述了一种基于 CPU 消耗的拒绝服务攻击,方法是创建一个具有很多冲突键(即具有相同哈希值的不同键)的 HashMap
。记录的攻击基于 URL 中的查询参数或 HTTP POST 数据中的键,但是 HashMap
的反序列化也容易受到这种攻击。
safeguards被放入 HashMap
以防止此类攻击的方法主要集中在带有 String
键的映射上。这足以防止基于 HTTP 的攻击,但很容易通过反序列化来规避,例如通过用 ArrayList
(其 hashCode 也是 predictable)包装每个 String
。 Java 8 包含一项提议 ( JEP-180 ) 以进一步改进 HashMap
面对许多冲突时的行为,它将保护扩展到所有实现 Comparable
的键类型,但这仍然允许基于 ArrayList
键的攻击。
这样做的结果是,攻击者可以设计一个字节流,使得从该流中反序列化对象所需的 CPU 工作量随流的大小呈二次方增长。
总结
通过控制反序列化过程的输入,攻击者可以触发任何 readObject
反序列化方法的调用。这样的方法理论上是可以允许字节码注入(inject)的。在实践中,肯定有可能以这种方式轻松耗尽内存或 CPU 资源,从而导致拒绝服务攻击。针对此类漏洞审核您的系统非常困难:您必须检查 readObject
的每个实现,包括第三方库和运行时库中的实现。
关于java - 在 Java 中反序列化不可信数据的安全影响是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19054460/