Skip to content

MASTG-KNOW-0021: Serialização de Objetos

Existem várias maneiras de serializar um objeto no Android:

API Java Serializable

Um objeto e seus dados podem ser representados como uma sequência de bytes. Isso é feito em Java por meio da serialização de objetos. A serialização não é inerentemente segura. É apenas um formato binário (ou representação) para armazenar dados localmente em um arquivo .ser. Criptografar e assinar dados serializados com HMAC é possível, desde que as chaves sejam armazenadas com segurança. Desserializar um objeto requer uma classe da mesma versão da classe usada para serializar o objeto. Após as classes serem alteradas, o ObjectInputStream não pode criar objetos a partir de arquivos .ser antigos. O exemplo abaixo mostra como criar uma classe Serializable implementando a interface Serializable.

import java.io.Serializable;

public class Person implements Serializable {
  private String firstName;
  private String lastName;

  public Person(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    }
  //..
  //getters, setters, etc
  //..

}

Agora você pode ler/escrever o objeto com ObjectInputStream/ObjectOutputStream em outra classe.

JSON

Existem várias maneiras de serializar o conteúdo de um objeto para JSON. O Android vem com as classes JSONObject e JSONArray. Uma ampla variedade de bibliotecas, incluindo GSON, Jackson, Moshi, também podem ser usadas. As principais diferenças entre as bibliotecas são se elas usam reflexão para compor o objeto, se suportam anotações, se criam objetos imutáveis e a quantidade de memória que utilizam. Observe que quase todas as representações JSON são baseadas em String e, portanto, imutáveis. Isso significa que qualquer segredo armazenado em JSON será mais difícil de remover da memória. O próprio JSON pode ser armazenado em qualquer lugar, por exemplo, um banco de dados (NoSQL) ou um arquivo. Você só precisa garantir que qualquer JSON que contenha segredos tenha sido apropriadamente protegido (por exemplo, criptografado/com HMAC). Consulte o capítulo "Armazenamento de Dados no Android" para mais detalhes. Um exemplo simples (do Guia do Usuário do GSON) de escrita e leitura de JSON com GSON segue. Neste exemplo, o conteúdo de uma instância de BagOfPrimitives é serializado em JSON:

class BagOfPrimitives {
  private int value1 = 1;
  private String value2 = "abc";
  private transient int value3 = 3;
  BagOfPrimitives() {
    // no-args constructor
  }
}

// Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);

// ==> json is {"value1":1,"value2":"abc"}

XML

Existem várias maneiras de serializar o conteúdo de um objeto para XML e vice-versa. O Android vem com a interface XmlPullParser, que permite uma análise de XML facilmente sustentável. Existem duas implementações no Android: KXmlParser e ExpatPullParser. O Guia do Desenvolvedor Android fornece uma ótima explicação sobre como usá-las. Além disso, existem várias alternativas, como um analisador SAX que vem com o runtime Java. Para mais informações, consulte um blogpost do ibm.com. Semelhante ao JSON, o XML tem o problema de trabalhar principalmente com base em String, o que significa que segredos do tipo String serão mais difíceis de remover da memória. Os dados XML podem ser armazenados em qualquer lugar (banco de dados, arquivos), mas precisam de proteção adicional em caso de segredos ou informações que não devem ser alteradas. Consulte o capítulo "Armazenamento de Dados no Android" para mais detalhes. Como afirmado anteriormente: o verdadeiro perigo no XML está no ataque XML eXternal Entity (XXE), pois pode permitir a leitura de fontes de dados externas ainda acessíveis dentro do aplicativo.

ORM

Existem bibliotecas que fornecem funcionalidade para armazenar diretamente o conteúdo de um objeto em um banco de dados e, em seguida, instanciar o objeto com o conteúdo do banco de dados. Isso é chamado de Mapeamento Objeto-Relacional (ORM). Bibliotecas que usam o banco de dados SQLite incluem

Realm, por outro lado, usa seu próprio banco de dados para armazenar o conteúdo de uma classe. A quantidade de proteção que o ORM pode fornecer depende principalmente de se o banco de dados está criptografado. Consulte o capítulo "Armazenamento de Dados no Android" para mais detalhes. O site do Realm inclui um bom exemplo de ORM Lite.

Parcelable

Parcelable é uma interface para classes cujas instâncias podem ser escritas e restauradas de um Parcel. Parcels são frequentemente usados para empacotar uma classe como parte de um Bundle para um Intent. Aqui está um exemplo da documentação do desenvolvedor Android que implementa Parcelable:

public class MyParcelable implements Parcelable {
     private int mData;

     public int describeContents() {
         return 0;
     }

     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mData);
     }

     public static final Parcelable.Creator<MyParcelable> CREATOR
             = new Parcelable.Creator<MyParcelable>() {
         public MyParcelable createFromParcel(Parcel in) {
             return new MyParcelable(in);
         }

         public MyParcelable[] newArray(int size) {
             return new MyParcelable[size];
         }
     };

     private MyParcelable(Parcel in) {
         mData = in.readInt();
     }
 }

Como esse mecanismo que envolve Parcels e Intents pode mudar ao longo do tempo, e o Parcelable pode conter ponteiros IBinder, não é recomendado armazenar dados em disco via Parcelable.

Protocol Buffers

Protocol Buffers do Google, são um mecanismo neutro em termos de plataforma e linguagem para serializar dados estruturados por meio do Formato de Dados Binários. Houve algumas vulnerabilidades com Protocol Buffers, como CVE-2015-5237. Observe que os Protocol Buffers não fornecem nenhuma proteção para confidencialidade: não há criptografia incorporada.