Comment utiliser les DTO Java pour renforcer la sécurité
11 octobre 2022
0 minutes de lectureEn Java, les objets de transfert de données (DTO) transportent des données entre des sous-systèmes. Il s’agit d’un modèle de conception d’entreprise qui permet d’agréger des données. Son objectif principal est de réduire le nombre d’appels système entre les sous-systèmes et, par conséquent, la surcharge générée.
Dans cet article, je vous explique comment les DTO sont utilisés dans les applications Java modernes, quels avantages votre application peut en tirer et comment ils peuvent renforcer la sécurité en évitant les fuites de données accidentelles.
Qu’est-ce qu’un POJO, un Java Bean et un objet valeur ?
Comme son nom l’indique, un Plain Old Java Object (POJO) est un objet Java ordinaire. Il peut s’agir de n’importe quelle classe, sans autre restriction que celles imposées par le langage Java. Les POJO sont créés pour favoriser la réutilisation et améliorer la lisibilité.
Un Java Bean est un POJO conforme à la norme JavaBean. Selon cette norme, toutes les propriétés sont privées et accessibles au moyen de méthodes getter et setter. Il doit également disposer d’un constructeur sans argument, ainsi que de quelques autres éléments.
Autrement dit, tous les Java Beans sont des POJO, mais tous les POJO ne sont pas des Java Beans.
Un objet valeur est un petit objet qui représente une entité de données simple. Toutefois, un objet valeur n’a généralement pas d’identité. Les objets valeur ne sont pas encore disponibles en Java, mais les responsables de la maintenance du JDK travaillent à leur ajout dans le cadre de JEP 401. Pour l’instant, nous devons créer un POJO pour remplir ce rôle.
Implémenter un objet de transfert de données
Un DTO peut être implémenté sous forme de POJO — ou de Java Bean, d’ailleurs. L’essentiel est qu’un DTO sépare les responsabilités entre des entités telles que la couche de présentation et le modèle de domaine, par exemple.
Prenons un petit service REST pour illustrer cela. Imaginons un café qui propose des cafés et accueille des clients. Ces deux éléments sont des entités de domaine distinctes dans le système. Pour connaître le café préféré d’un client, je vais créer une API qui fournit les données agrégées représentées par le FavoriteCoffeDTO.

Le code ressemble à ceci :
Dans l’implémentation ci-dessus, j’ai séparé la couche de domaine de la couche de présentation. Mon contrôleur peut ainsi se charger de mapper les deux entités de domaine vers le DTO.
Dans cet exemple, j’ai défini les champs comme privés. Je dois donc créer des méthodes getter et setter pour y accéder. Pour leurs DTO, les utilisateurs choisissent souvent de suivre la norme JavaBean, en totalité ou en partie. Ce n’est pas obligatoire, bien sûr : vous êtes libre de choisir la méthode qui répond à vos besoins. Vous pouvez aussi rendre tous les champs publics et y accéder directement (comme dans l’exemple ci-dessous), ou rendre l’objet immuable à l’aide d’un constructeur prenant tous les arguments et de quelques méthodes getter.
Enfin, si vous utilisez une version récente de Java, vous pouvez envisager d’utiliser les records Java pour vos DTO. Les records Java sont des classes immuables simples qui fournissent automatiquement un constructeur prenant tous les arguments, des méthodes d’accès, toString() et hashCode(), sans qu’il soit nécessaire de les définir. Votre code est ainsi plus concis et plus lisible. Notez que les records ne respectent pas la spécification Java Bean, car leurs méthodes d’accès ne comportent pas le préfixe get ou set.
Qu’est-ce qui fait un bon DTO ?
Un DTO sert à transporter des données entre des processus. Un bon DTO ne contient donc que les informations nécessaires à la partie concernée du système. Dans notre exemple d’API, nous devons uniquement renvoyer le nom du client et sa commande de café préférée. Inutile d’ajouter autre chose, comme de la logique métier. En règle générale, vos DTO doivent rester aussi simples, compacts et clairs que possible.
De plus, après son initialisation, l’état d’un DTO ne devrait pas changer ni évoluer. Une structure de données immuable est donc idéale pour un DTO. Comme un DTO ne transporte que des données qui ne doivent pas être modifiées, un record Java convient parfaitement — d’autant que les bibliothèques de sérialisation JSON comme Jackson prennent en charge les records Java.
Considérations de sécurité liées aux DTO
Nous avons déjà vu que le modèle de DTO dissocie le modèle de domaine de la couche de présentation. Des DTO simples, qui ne contiennent que les données nécessaires au sous-système ou à l’API concernés et aucune logique métier, peuvent également renforcer la sécurité.
Dans de nombreuses preuves de concept, on constate que les entrées du domaine sont renvoyées dans leur intégralité. Des données qui n’ont pas lieu d’être accessibles en dehors du système peuvent ainsi l’être, avec un risque de fuite.
Imaginons que notre API dispose d’une fonction permettant de trouver tous les clients, mais qu’elle n’utilise pas de DTO :
Si notre objet client est identique à celui de l’exemple précédent, nous affichons déjà trop d’informations. Avons-nous vraiment besoin de l’id ou de la liste des coffees préférés ? La situation empire si nous décidons d’ajouter d’autres informations au client, comme son adresse personnelle.
Si nous ne filtrons pas les données dans notre endpoint, nous provoquons soudainement une violation de données, car communiquer le nom complet et l’adresse personnelle d’une personne constitue une atteinte à la vie privée dans de nombreux pays. Un DTO aurait permis de dissocier l’API du modèle de données et d’éviter ce problème, puisque le contrôleur de mapping n’aurait renseigné que les champs nécessaires du DTO. Même si nous ajoutons ensuite des éléments à notre modèle de domaine, l’utilisation d’un DTO nous évite de divulguer des informations personnelles identifiables.
Recommandations
Utiliser des DTO en Java pour dissocier les sous-systèmes est généralement une bonne idée. Du point de vue de l’ingénierie, cela réduit les allers-retours entre les différentes couches ; du point de vue de la sécurité, cela contribue à prévenir les fuites de données accidentelles. Je vous recommande de créer des DTO spécifiques et d’en limiter la réutilisation. Si vous réutilisez vos DTO pour différentes fonctions, veillez à bien comprendre où ils sont utilisés avant de les modifier.
En règle générale, vos DTO doivent rester concis, dépourvus de logique métier dans la mesure du possible et ne fournir que les données nécessaires à des fonctions précises. Enfin, l’immutabilité me semble particulièrement adaptée aux DTO. Les records Java — disponibles en version finale depuis Java 16 — constituent donc un excellent moyen d’implémenter des DTO en Java.
Consultez les ressources suivantes pour en savoir plus sur la sécurité Java :
Sérialisation et désérialisation en Java : comprendre la vulnérabilité de désérialisation Java
10 bonnes pratiques pour créer un conteneur Java avec Docker
Journalisation Java : que faut-il journaliser et que faut-il éviter ?
Vous pouvez également essayer gratuitement notre outil de vérification de code Java en ligne pour voir comment le moteur Snyk Code analyse votre code afin d’y détecter les problèmes de sécurité et de qualité.
FAQ
Qu’est-ce qu’un DTO ?
DTO signifie Data Transfer Object (objet de transfert de données). Il s’agit d’un objet qui transporte des données entre différents processus d’une application. Un DTO est conçu spécifiquement pour réduire le nombre d’appels de méthode entre le client et le serveur en agrégeant les données. Il évite également le couplage étroit entre des entités telles que le modèle de domaine et la couche de présentation d’une application.
Qu’est-ce qu’un DTO en Java ?
En Java, un objet de transfert de données est généralement un POJO (Plain Old Java Object) dépourvu de logique métier. Il présente habituellement une structure de données plate, adaptée précisément à l’objectif de la transaction entre les méthodes qui l’utilisent. Les DTO Java peuvent suivre la convention JavaBean, avec des champs privés et des méthodes getter et setter, mais ce n’est pas obligatoire.
Un DTO est-il la même chose qu’un POJO ?
En bref, un DTO est un POJO, mais tous les POJO ne sont pas des DTO. Un objet de transfert de données est un POJO spécifique, destiné à transporter des données entre des processus.
L’utilisation de DTO est-elle une bonne pratique ?
Oui. Bien implémentés, les DTO réduisent le couplage étroit et le nombre d’appels de méthode, ce qui renforce la sécurité et limite les fuites de données.
Quelle est la différence entre un DAO et un DTO ?
DAO signifie Data Access Object (objet d’accès aux données). Ce modèle permet de dissocier la logique métier de la couche de persistance. Les DAO servent souvent aux opérations CRUD, comme la mise à jour, la suppression et l’enregistrement. Un DTO est un objet destiné exclusivement au transport de données entre des sous-systèmes et ne doit pas contenir de logique métier.
Lancez-vous dans les compétitions Capture The Flag
Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.



