Como usar DTOs em Java para manter a segurança
11 de outubro de 2022
0 minutos de leituraOs objetos de transferência de dados (DTOs, na sigla em inglês) em Java transportam dados entre subsistemas. Esse é um padrão de projeto corporativo para agregar dados. Seu principal objetivo é reduzir o número de chamadas ao sistema necessárias entre os subsistemas, diminuindo a sobrecarga gerada.
Neste artigo, explico como os DTOs são usados em aplicações Java modernas, quais benefícios podem trazer para sua aplicação e como ajudam a aumentar a segurança ao evitar vazamentos acidentais de dados.
O que são POJO, Java Bean e Value Object
Como o nome sugere, um Plain Old Java Object (POJO) é um objeto Java comum. Pode ser qualquer classe e não está sujeito a restrições específicas além das definidas pela linguagem Java. POJOs são criados para promover a reutilização e aumentar a legibilidade.
Um Java Bean é um POJO que segue o padrão JavaBean. De acordo com esse padrão, todas as propriedades são privadas e acessadas por métodos getter e setter. Além disso, deve haver um construtor sem argumentos, entre outros requisitos.
Isso significa que todos os Java Beans são POJOs, mas nem todos os POJOs são Java Beans.
Um Value Object é um objeto pequeno que representa uma entidade de dados simples. No entanto, normalmente ele não tem uma identidade. Os Value Objects ainda não estão disponíveis em Java, mas os mantenedores do JDK estão trabalhando para adicioná-los como parte do JEP 401. Por enquanto, precisamos criar um POJO para fazer esse trabalho.
Como implementar um objeto de transferência de dados
Um DTO pode ser implementado como um POJO — ou, nesse caso, como um Java Bean. O mais importante é que ele separe as responsabilidades entre entidades, como a camada de apresentação e o modelo de domínio, por exemplo.
Vamos usar um pequeno serviço REST para explicar. Imagine uma cafeteria com cafés e clientes. No sistema, cada um deles é uma entidade de domínio separada. Para descobrir qual é o café favorito de um cliente, vou criar uma API que fornece os dados agregados representados em FavoriteCoffeDTO.

O código fica mais ou menos assim:
Na implementação acima, separei a camada de domínio da camada de apresentação. Assim, meu controller pode mapear as duas entidades de domínio para o DTO.
Neste exemplo, defini os campos como privados, então preciso criar métodos getter e setter para acessá-los. Muitas pessoas optam por seguir o padrão JavaBean totalmente ou em parte ao criar DTOs. Isso não é obrigatório, é claro: você pode escolher o método que melhor atende às suas necessidades. Outras opções incluem tornar todos os campos públicos e acessá-los diretamente, como no exemplo abaixo, ou tornar o objeto imutável com um construtor que receba todos os argumentos e alguns métodos getter.
Por fim, se você atualizou para uma versão mais recente do Java, pode usar Java Records nos seus DTOs. Java Records são classes imutáveis e simples que fornecem automaticamente um construtor com todos os argumentos, métodos de acesso, toString() e hashCode(), sem que seja necessário defini-los. Isso deixa o código mais enxuto e legível. Vale notar que os records não seguem a especificação Java Bean, pois os métodos de acesso não têm o prefixo get nem set.
O que torna um DTO bom?
O objetivo de um DTO é transportar dados entre processos. Por isso, um bom DTO contém apenas as informações necessárias para aquela parte específica do sistema. No exemplo da API, precisamos retornar somente o nome do cliente e o pedido do café favorito dele. Não é necessário incluir mais nada, como lógica de negócios. A recomendação geral é manter seus DTOs tão simples, pequenos e diretos quanto possível.
Além disso, depois de inicializado, o estado de um DTO não deve mudar nem evoluir. Por isso, uma estrutura de dados imutável é ideal para um DTO. Como ele transporta apenas dados que não devem ser alterados, um Java Record é uma ótima opção — especialmente porque bibliotecas de serialização JSON, como Jackson, dão suporte a Java Records.
Considerações de segurança para DTOs
Como vimos, esse padrão com DTOs desacopla o modelo de domínio da camada de apresentação. DTOs simples, que contêm apenas os dados necessários para determinado subsistema ou API e não incluem lógica de negócios, também podem aumentar a segurança.
Em muitas provas de conceito, vemos que os dados das entidades de domínio são expostos por completo. Isso pode disponibilizar dados desnecessários fora do sistema e causar possíveis vazamentos.
Imagine que nossa API tenha uma função para encontrar todos os clientes, mas não use um DTO:
Se o objeto de cliente for igual ao do exemplo anterior, já estaremos exibindo informações demais. Será que precisamos mesmo do id ou da lista de coffees favoritos? A situação piora se decidirmos adicionar mais informações ao cliente, como o endereço residencial.
Se não filtrarmos os dados no endpoint, podemos causar uma violação de dados, já que fornecer o nome completo e o endereço residencial é considerado uma violação de privacidade em muitos países. Desacoplar a API do modelo de dados com um DTO teria evitado isso, pois o controller responsável pelo mapeamento preencheria apenas os campos necessários no DTO. Mesmo que depois decidamos adicionar algo ao modelo de domínio, usar um DTO impede que informações de identificação pessoal sejam expostas.
Recomendações
Em geral, usar DTOs em Java para desacoplar subsistemas é uma boa ideia. Do ponto de vista da engenharia, isso reduz as idas e vindas entre as diferentes camadas. Do ponto de vista da segurança, ajuda a evitar vazamentos acidentais de dados. Recomendo criar DTOs específicos e limitar a reutilização. Se você reutilizar seus DTOs em diferentes funções, entenda claramente onde eles são usados antes de fazer alterações.
Em geral, mantenha seus DTOs concisos, sem lógica de negócios sempre que possível, e forneça apenas os dados necessários para funções específicas. Por fim, acredito que a imutabilidade combina naturalmente com DTOs. Por isso, Java Records — lançados oficialmente no Java 16 — são uma ótima forma de implementar DTOs em Java.
Confira os recursos a seguir para saber mais sobre segurança em Java:
Serialização e desserialização em Java: entenda a vulnerabilidade de desserialização do Java
10 práticas recomendadas para criar um contêiner Java com Docker
Você também pode experimentar gratuitamente nossa ferramenta online de análise de código Java para ver como o Snyk Code analisa seu código em busca de problemas de segurança e qualidade.
Perguntas frequentes
O que é um DTO?
DTO é a sigla em inglês para Data Transfer Object (objeto de transferência de dados). É um objeto que transporta dados entre diferentes processos em uma aplicação. Um DTO foi projetado especificamente para reduzir o número de chamadas de método entre cliente e servidor, agregando dados. Ele também evita o acoplamento estreito entre entidades, como o modelo de domínio e a camada de apresentação de uma aplicação.
O que é um DTO em Java?
Em Java, um objeto de transferência de dados costuma ser um POJO (Plain Old Java Object, ou objeto Java simples), sem lógica de negócios. Geralmente, ele tem uma estrutura de dados plana, adequada especificamente à finalidade da transação entre os métodos em que é usado. Os DTOs em Java podem seguir a convenção JavaBean, com campos privados e métodos getter e setter, mas isso não é obrigatório.
DTO e POJO são a mesma coisa?
Resumindo, um DTO é um POJO, mas nem todo POJO é um DTO. Um objeto de transferência de dados é um POJO específico para transportar dados entre processos.
Usar DTOs é uma boa prática?
Sim. Quando bem implementados, os DTOs reduzem o acoplamento estreito e o número de chamadas de método, o que aumenta a segurança e reduz os vazamentos de dados.
Qual é a diferença entre DAO e DTO?
DAO é a sigla em inglês para Data Access Object (objeto de acesso a dados) e é usado em um padrão que desacopla a lógica de negócios da camada de persistência. DAOs costumam ser usados em operações CRUD, como atualizar, excluir e salvar. Um DTO é um objeto destinado exclusivamente a transportar dados entre subsistemas e não deve conter lógica de negócios.
Comece a jogar Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo à gravação sob demanda do nosso workshop virtual introdutório.



