DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on

Capítulo 12: Serialização - Item 85: Prefira alternativas à serialização Java

A Serialização ainda é usada hoje, mas com muita cautela. Ela foi amplamente utilizada no passado para persistência de objetos e comunicação entre sistemas, mas devido a diversos problemas de segurança e eficiência, seu uso tem diminuído.

Atualmente, frameworks modernos e tecnologias como JSON, XML, Protobuf e Avro são preferidos para troca de dados, pois são mais seguros, interoperáveis e eficientes. No entanto, a serialização Java ainda pode ser encontrada em sistemas legados e em aplicações que precisam de compatibilidade com tecnologias antigas.

Se for realmente necessário usar serialização, recomenda-se adotar boas práticas de segurança, como filtragem de objetos e evitar desserialização de fontes não confiáveis.

Item 85: Prefira alternativas à serialização Java

O que é Serialização?

  • Processo de transformar um objeto em uma sequência de bytes para armazenamento ou transmissão.
  • Desserialização é o processo inverso, reconstruindo o objeto a partir dos bytes serializados.
  • Utiliza a interface Serializable no Java.

Problemas da Serialização Java

1. Superfície de Ataque Grande

  • O método readObject atua como um "construtor mágico", podendo instanciar objetos inesperados.
  • Qualquer classe que implemente Serializable pode ser um ponto de exploração.

2. Vulnerabilidades de Segurança

  • Possibilidade de execução remota de código (RCE) ao desserializar objetos de origem desconhecida.
  • Uso de gadgets (métodos chamados automaticamente durante a desserialização) para criar cadeias de ataque.

3. Bombas de Desserialização

  • Objetos que exigem grande poder computacional para serem desserializados.
  • Exemplo: HashSet profundamente aninhado.

Exemplo de bomba de desserialização:

import java.io.*;
import java.util.HashSet;

public class DeserializationBomb {
    public static void main(String[] args) throws Exception {
        HashSet<Object> root = new HashSet<>();
        HashSet<Object> s1 = root;
        HashSet<Object> s2;

        for (int i = 0; i < 100; i++) {
            s2 = new HashSet<>();
            s1.add(s2);
            s1 = s2;
        }

        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("bomb.ser"))) {
            out.writeObject(root);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Alternativas à Serialização Java
JSON

  • Leve, legível e amplamente suportado. Exemplo com Gson:
import com.google.gson.Gson;

class Pessoa {
    String nome;
    int idade;
}

public class JsonExample {
    public static void main(String[] args) {
        Gson gson = new Gson();
        Pessoa pessoa = new Pessoa();
        pessoa.nome = "João";
        pessoa.idade = 30;

        String json = gson.toJson(pessoa);
        System.out.println(json);
    }
}
Enter fullscreen mode Exit fullscreen mode

Protocol Buffers (Protobuf)

  • Binário e eficiente.
  • Necessita da definição de esquemas .proto.

Como Mitigar Riscos se a Serialização for Necessária

  • Evite Desserialização de Dados Não Confiáveis
  • Use Filtragem de Objetos (ObjectInputFilter desde Java 9)
ObjectInputFilter filter = info -> {
    if (info.serialClass() != null && info.serialClass().getName().equals("MinhaClasseSegura")) {
        return ObjectInputFilter.Status.ALLOWED;
    }
    return ObjectInputFilter.Status.REJECTED;
};

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("objeto.ser"));
ois.setObjectInputFilter(filter);
Object obj = ois.readObject();
Enter fullscreen mode Exit fullscreen mode

Utilize Lista Branca em vez de Lista Negra

  • Permita apenas classes explícitas na desserialização.

Conclusão

  • Evite ao máximo a Serialização Java em sistemas novos.
  • Prefira formatos mais seguros e eficientes como JSON e Protobuf.
  • Se precisar desserializar objetos, use filtragem rigorosa para evitar ataques.

Exemplo do livro:

Image description

Top comments (0)