解决方法
代码注入
可以使一个readObject实现打开任意字节码注入的门.只需从流中读取一个字节数组,并将其传递给ClassLoader.defineClass和ClassLoader.resolveClass()(参见the former和the later的javadoc).我不知道这种实现的用途是什么,但是这是可能的.
记忆疲惫
编写安全的readObject方法很难.直到somewhat recently,HashMap的readObject方法包含以下几行.
int numBuckets = s.readInt(); table = new Entry[numBuckets];
这样一来,攻击者就可以轻松地分配几GB的内存,只需要几十个字节的序列化数据,这样就可以在任何时间内使用OutOfMemoryError来关闭系统.
Hashtable的current implementation似乎仍然容易受到类似的攻击;它基于元素的数量和负载因子来计算分配的数组的大小,但是在loadFactor中没有对不合理的值进行保护,因此我们可以轻松地请求为表中的每个元素分配十亿个时隙.
修复HashMap中的漏洞是作为更改的一部分,以解决与基于散列的地图相关的另一个安全问题. CVE-2012-2739通过创建具有非常多的冲突键(即具有相同哈希值的不同键)的HashMap来描述基于cpu消耗的拒绝服务攻击.记录的攻击基于HTTP POST数据中的URL或密钥中的查询参数,但是HashMap的反序列化也容易受到此攻击的影响.
放在HashMap中以防止这种类型的攻击的safeguards集中在使用String键的地图上.这足以防止基于HTTP的攻击,但很容易绕过反序列化,例如通过用ArrayList(其hashCode也是predictable)包装每个String. Java 8包括一个提案(JEP-180),以进一步改善HashMap在面临许多冲突时的行为,将保护扩展到实现Comparable的所有关键类型,但仍然允许基于ArrayList键的攻击.
这样做的结果是,攻击者可以设计一个字节流,使得从该流反序列化对象所需的cpu工作量随着流的大小而二次增长.
概要
通过控制反序列化过程的输入,攻击者可以触发任何readObject反序列化方法的调用.理论上这种方法可以允许字节码注入.实际上,这样可以轻松地耗尽内存或cpu资源,导致拒绝服务攻击.审查您的系统是否存在这种漏洞非常困难:您必须检查readObject的每个实现,包括第三方库和运行时库中的所有实现.