Java 使用xstream进行恶意对象注入

Java 使用xstream进行恶意对象注入,java,security,xstream,Java,Security,Xstream,我可以安全地使用XStream来处理来自系统外部的XML吗? 使用xstream处理“潜在恶意XML”的最佳实践是什么 比方说,我的代码中有这样一个类: package hazard; class Dangerous { public Dangerous() { AtomicBomb.getInstance().nuke(); } } 恶意用户可能会提交XML文件,例如: <hazard.Dangerous/> 并使XStream调用nu

我可以安全地使用XStream来处理来自系统外部的XML吗? 使用xstream处理“潜在恶意XML”的最佳实践是什么

比方说,我的代码中有这样一个类:

 package hazard;
 class Dangerous {
    public Dangerous() {
       AtomicBomb.getInstance().nuke();
    }
 }
恶意用户可能会提交XML文件,例如:

 <hazard.Dangerous/>

并使XStream调用nuke()方法

这个例子很有理论性。正如前面所指出的,我不希望构造函数做这种事情。但是我可以肯定的是,类路径中任何可用库中的构造函数都不会有这样的问题(例如,分配一些资源,比如文件描述符)

关键是,发送XML文件允许攻击者创建任意对象。更现实的方法可能是使用某个类而不是另一个类

public class Foo<T implements Bar> {
    private T t;
    // Getters/setters ...
}

public interface Bar {
   public void bar();
}

public class Bar1 implements Bar {
   // ...
}

public class Bar2 implements Bar {
   // ...
}
公共类Foo{
私人T;
//接受者/接受者。。。
}
公共接口栏{
公共空白栏();
}
公共类Bar1实现Bar{
// ...
}
公共类Bar2实现了Bar{
// ...
}
使用(恶意)XML输入:

<foo>
  <!-- I expect bar1 -->
  <package.Bar2/>
</foo>

现在使用Java代码:

Bar<Foo1> bar = (Bar<Foo1>) xstream.fromXML(xml);
// I expect to have a bar1 but I have a bar2.
bar.getT().foo();
Bar=(Bar)xstream.fromXML(xml);
//我想喝一杯啤酒,但我喝了一杯啤酒。
bar.getT().foo();
乍一看,解决方案是提供一个自定义映射器(在realClass()方法中完成的工作)。

绝不允许xstream(或任何其他序列化框架)封送任何内容,除非是干净的纯JavaBean(getter和setter)

更新: 您提到的关于使用映射器的理论应该是可行的,尽管它需要您构建一些脚手架和自定义配置。另一种方法是使用XStream的特性指定用于解析类的专用类加载器。您将尝试将所有应允许由xstream进行封送的类放在一个单独的JAR中(将其视为一个域模块)。然后创建一个干净的类加载器,只加载那个JAR并将其分配给xstream。这样,xstream就不会知道其作用域之外的任何类,无法反序列化任何您不希望它反序列化的内容

试试像这样的东西

ClassLoader bootstrapClassLoader = ClassLoader.getSystemClassLoader().getParent();
List urls = new ArrayList();
urls.add(new File("yourJarOfXstreamBeanClasses.jar").toURL());
ClassLoader xstreamClassLoader = new URLClassLoader(urls.toArray(new URL[0]), bootstrapClassLoader);
XStream xstream = new XStream();
xstream.setClassLoader(xstreamClassLoader);

如果开发团队中有人调用
DangerousClass()
,该怎么办?XStream将持久化该对象,如果您在中读取该对象,并且XML已更改,那么您最多将收到一个ClassCastException

尝试更改类的结构,然后使用XStream读入,您将得到错误。如果保留将在DB查询中使用的参数,请确保使用准备好的语句。如果你把代码放在一个可能损坏系统的对象构造函数中,那就是你糟糕的编码实践。使用构造函数初始化值,而不是调用代码,这就是方法的用途


如果您正确地编码,就不会有与XStream相关的安全风险

有多种方法可以核化Java实例。首先,我不允许系统传递任意XML。只需传递一个双值
2.2250738585072012e-308
就可以杀死除最新版本以外的所有Java。为什么要从对象的构造函数调用“危险”代码?我已经研究了很多默认Java序列化,很难以安全的方式进行。我快速地看了一下XStream,您的谨慎肯定是正确的。如果您确实必须从不受信任的源获取数据,我建议将这些类白名单到某个有限的POJO集合中,但我不知道如何使用XStream实现这一点。大多数Java核心构造函数表现良好,但甚至不是全部。第三方LIB肯定更糟糕。事实上,至少在“增强”模式下,根本不调用构造函数。事实上,但问题是“如何/应该防止XStream从恶意XML实例化意外类?”事实上,这是相当多的工作。我觉得JAXB更适合这种情况。