在Java中反序列化不受信任的数据有什么安全影响? [英] What is the security impact of deserializing untrusted data in Java?
问题描述
反序列化不受信任的数据是否安全,只要我的代码不对反序列化对象的状态或类进行任何假设,或者仅仅反序列化的行为是否会导致意外操作?
Is it safe to deserialize untrusted data, provided my code makes no assumptions about the state or class of the deserialized object, or can the mere act of deserializing cause undesired operation?
(威胁模型:攻击者可以自由修改序列化数据,但这就是他所能做的)
(Threat model: The attacker may freely modify the serialized data, but that's all he can do)
推荐答案
反序列化本身已经不安全了。可序列化的类可以定义 readObject
方法(另请参阅规范),当要从流中反序列化此类的对象时调用。攻击者无法提供此代码,但使用精心设计的输入,她可以调用任何此类 readObject
方法,该方法位于类路径上,具有任何输入。
Deserialization itself can already be unsafe. A serializable class may define a readObject
method (see also the specification), which is called when an object of this class is going to be deserialized from the stream. The attacker cannot provide this code, but using a crafted input she can invoke any such readObject
method that is on your classpath, with any input.
可以创建 readObject
实现打开任意字节码注入的大门。只需从流中读取一个字节数组并将其传递给 ClassLoader.defineClass
和 ClassLoader.resolveClass()
(参见javadoc for 前者和后来的)。我不知道这种实现的用途是什么,但它是可能的。
It is possible to make a readObject
implementation that opens the door to arbitrary bytecode injection. Simply read a byte array from the stream and pass it to ClassLoader.defineClass
and ClassLoader.resolveClass()
(see the javadoc for the former and the later). I don't know what the use of such an implementation would be, but it is possible.
编写安全的 readObject
方法很难。直至最近
HashMap
的 readObject
方法包含以下几行。
Writing secure readObject
methods is hard. Up until somewhat recently the readObject
method of HashMap
contained the following lines.
int numBuckets = s.readInt();
table = new Entry[numBuckets];
这使攻击者很容易分配几千兆字节的内存,只需几十个字节序列化数据,系统会立即使用 OutOfMemoryError
关闭系统。
This makes it very easy for an attacker to allocate several gigabytes of memory with just a few dozen bytes of serialized data, which will have your system down with an OutOfMemoryError
in no time.
当前实施 code> Hashtable 似乎仍然容易受到类似的攻击;它根据元素的数量和加载因子计算分配数组的大小,但是对于 loadFactor
中的不合理值没有防范,所以我们可以轻松请求为表中的每个元素分配10亿个槽。
The current implementation of Hashtable
seems to still be vulnerable to a similar attack; it computes the size of the allocated array based on the number of elements and the load factor, but there is no guard in place against unreasonable values in loadFactor
, so we can easily request a billion slots be allocated for each element in the table.
修复 HashMap中的漏洞
是作为更改的一部分完成的,以解决与基于散列的地图相关的另一个安全问题。 CVE-2012-2739 描述了拒绝 - 通过使用非常多的冲突密钥(即具有相同哈希值的不同密钥)创建 HashMap
,基于CPU消耗的服务攻击。记录的攻击基于HTTP POST数据中的URL或密钥中的查询参数,但 HashMap
的反序列化也容易受到此攻击。
Fixing the vulnerability in HashMap
was done as part of changes to address another security issue related to hash-based maps. CVE-2012-2739 describes a denial-of-servic attack based on CPU consumption by creating a HashMap
with very many colliding keys (i.e. distinct keys with the same hash value). The documented attacks are based on query parameters in URLs or keys in HTTP POST data, but deserialization of a HashMap
is also vulnerable to this attack.
HashMap 以防止此类攻击的noreferrer>安全措施集中在带有 String
键。这足以防止基于HTTP的攻击,但很容易通过反序列化来避免,例如,通过用 ArrayList
包装每个 String
(其hashCode也是可预测的)。 Java 8包含一个提议( JEP-180 )以进一步改善<的行为code> HashMap 面对许多冲突,它将保护扩展到实现 Comparable
的所有密钥类型,但仍允许基于 ArrayList
键的攻击。
The safeguards that were put into HashMap
to prevent this type of attack are focussed on maps with String
keys. This is adequate to prevent the HTTP-based attacks, but is easily circumvented with deserialization, e.g. by wrapping each String
with an ArrayList
(whose hashCode is also predictable). Java 8 includes a proposal (JEP-180) to further improve the behaviour of HashMap
in the face of many collisions, which extends the protection to all key types that implements Comparable
, but that still allows an attack based on ArrayList
keys.
这样做的结果是,攻击者可以设计一个字节流,以便从该流中反序列化对象所需的CPU工作量随着大小的增加而呈二次方式增长流。
The upshot of this is that is possible for the attacker to engineer a byte streams such that the CPU effort it takes to deserialize an object from this stream grows quadratically with the size of the stream.
通过控制反序列化过程的输入,攻击者可以触发调用任何 readObject
反序列化方法。理论上,这种方法可以允许字节码注入。实际上,以这种方式容易耗尽内存或CPU资源肯定是可能的,从而导致拒绝服务攻击。针对此类漏洞审核您的系统非常困难:您必须检查 readObject
的每个实现,包括第三方库和运行时库中的那些。
By controlling the input to the deserialization process an attacker can trigger the invocation of any readObject
deserialization-method. It is theoretically possible for such a method to allow bytecode injection. In practice it is certainly possible to easily exhaust memory or CPU resources this way, resulting in denial-of-service attacks. Auditing your system against such vulnerabilities is very difficult: you have to check every implementation of readObject
, including those in third-party libraries and the runtime library.
这篇关于在Java中反序列化不受信任的数据有什么安全影响?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!