CodeQL 文档

用户控制数据的反序列化

ID: java/unsafe-deserialization
Kind: path-problem
Security severity: 9.8
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-502
Query suites:
   - java-code-scanning.qls
   - java-security-extended.qls
   - java-security-and-quality.qls

单击以在 CodeQL 存储库中查看查询

使用允许构建任意可序列化对象的任何反序列化框架反序列化不受信任的数据很容易被利用,并且在许多情况下允许攻击者执行任意代码。甚至在反序列化对象返回给反序列化方法的调用者之前,也可能执行了很多代码,包括静态初始化程序、构造函数和终结器。字段的自动反序列化意味着攻击者可以制作嵌套的对象组合,在这些对象上执行的初始化代码可能会产生意想不到的影响,例如执行任意代码。

有很多不同的序列化框架。此查询目前支持 Kryo、XmlDecoder、XStream、SnakeYaml、JYaml、JsonIO、YAMLBeans、HessianBurlap、Castor、Burlap、Jackson、Jabsorb、Jodd JSON、Flexjson、Gson、JMS 和通过 ObjectInputStream/ObjectOutputStream 进行的 Java IO 序列化。

建议

如果可能,请避免反序列化不受信任的数据。如果架构允许,那么使用其他格式而不是序列化对象,例如 JSON 或 XML。但是,这些格式不应反序列化为复杂对象,因为这会提供进一步的攻击机会。例如,可以通过 XStream 和 XmlDecoder 等库进行基于 XML 的反序列化攻击。

或者,严格控制的白名单可以限制代码的漏洞,但请注意所谓的绕过小工具的存在,它可以规避此类保护措施。

此查询支持的特定框架的建议

FastJson - com.alibaba:fastjson

  • 默认安全:部分

  • 建议:在反序列化不受信任的数据之前,使用参数 true 调用 com.alibaba.fastjson.parser.ParserConfig#setSafeMode

FasterXML - com.fasterxml.jackson.core:jackson-databind

  • 默认安全:是

  • 建议:不要调用 com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping,也不要使用 com.fasterxml.jackson.annotation.JsonTypeInfo 注释任何对象字段,并向注释传递 CLASSMINIMAL_CLASS 值。阅读 本指南

Kryo - com.esotericsoftware:kryocom.esotericsoftware:kryo5

  • 默认安全com.esotericsoftware:kryo5 为是,com.esotericsoftware:kryo >= v5.0.0 为是

  • 建议:不要在任何可能反序列化不受信任数据的 Kryo 实例上使用参数 false 调用 com.esotericsoftware.kryo(5).Kryo#setRegistrationRequired

ObjectInputStream - Java 标准

  • 默认安全:否

  • 建议:使用验证输入流,例如 org.apache.commons.io.serialization.ValidatingObjectInputStream

SnakeYAML - org.yaml:snakeyaml

  • 默认安全:否

  • 建议:在使用 org.yaml.snakeyaml.Yaml 的构造函数反序列化不受信任的数据之前,向其传递 org.yaml.snakeyaml.constructor.SafeConstructor 的实例。

XML Decoder - 标准 Java

  • 默认安全:否

  • 建议:不要与不受信任的用户输入一起使用。

ObjectMesssage - Java EE/Jakarta EE

  • 默认安全:取决于 JMS 实现。

  • 建议:不要与不受信任的用户输入一起使用。

示例

以下示例直接在从不受信任数据构建的 ObjectInputStream 上调用 readObject,因此本质上是不安全的。

public MyObject {
  public int field;
  MyObject(int field) {
    this.field = field;
  }
}

public MyObject deserialize(Socket sock) {
  try(ObjectInputStream in = new ObjectInputStream(sock.getInputStream())) {
    return (MyObject)in.readObject(); // unsafe
  }
}

将通信协议重写为仅依赖从输入流读取原始类型,即可消除漏洞。

public MyObject deserialize(Socket sock) {
  try(DataInputStream in = new DataInputStream(sock.getInputStream())) {
    return new MyObject(in.readInt());
  }
}

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私