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