La librairie de chiffrement JASYPT et Spring Boot

Introduction

La sécurité, c'est comme la propreté... c'est l'affaire de tous ! En tant que développeur, il nous appartient de sécuriser nos applications. Une erreur fréquente est de laisser des informations sensibles, en clair, dans nos fichiers de configuration. En effet, il suffit alors d'avoir accès au dépôt de sources, pour accéder à ces propriétés et donc, aux systèmes concernés.

Si on prend l'exemple des propriétés de connexion à une base de données, on peut alors prendre un raccourci et valider le constat que : “chaque personne qui a accès au dépôt de sources a accès à la base de données”. Votre voisin de bureau qui travaille sur un autre projet a accès à votre base de données. Est-ce normal ?

On tendrait à penser que c’est “sécurisé” en se disant que, “de toute façon, seules les personnes de l’entreprise/l'activité possèdent un accès aux sources”. Alors, cela reviendrait à se dire que l’on peut laisser nos clés de maison sur la porte car seuls nos voisins sont susceptibles de passer dans la rue. C’est une mauvaise pratique, il y a trop d'hypothèses, et donc, on prend un risque.

La philosophie est la suivante : il n’y pas de confiance implicite, il faut toujours vérifier qui a accès et, à quoi. On commence, sans aucune permission et, on les ouvre au fur et à mesure des besoins de travail (uniquement de manière temporaire si possible comme préconisé par le principe de least privilege ).

Pour une application, l’idéal serait une gestion décentralisée des accès ainsi qu’une récupération des mots de passe via des systèmes de coffre forts/gestion des privilèges. Ce n’est pas toujours possible et ces infrastructures (idéales) ont des coûts. Ici, nous allons voir comment élever le niveau d’un “petit” cran avec la librairie Jasypt.

La librairie JAsYPT késako ?

Jasypt (JAva Simplified encrYPTion) est une librairie open source créée par Daniel Fernándèz (thymeleaf) qui permet d’ajouter des fonctionnalités de chiffrement avec peu d’effort et sans connaissance approfondie en cryptographie.

Elle gère le chiffrement de chaîne de caractères, de nombres, de fichiers... Elle propose l’utilisation de plusieurs algorithmes d’encodage, s’intègre avec Spring, Hibernate et offre une CLI pour faciliter la vie des développeurs.

Bref, c’est simple et puissant ! Nous allons donc l’utiliser sur une application Spring Boot exemple.

NB. Les algorithmes de chiffrement ne sont pas implémentés dans le projet de la librairie. Cette dernière ne réinvente pas la roue et utilise des algorithmes fournis par différentes JCE (Java Cryptography Extension).

Préparation du terrain

Pour l'exemple, nous allons mettre en place une application Spring Boot qui se connecte à une base de données.

Squelette Spring Boot

Initialiser un projet avec l'outil Spring Initializr et sélectionner les dépendances à Spring Data JPA et PostgreSQL Driver.

article-jasypt-1

Squelette Postgres

Initialiser une base de données avec Postgres à faire tourner où vous voulez. Ici, je vous propose dans un container docker (https://hub.docker.com/_/postgres)

version: '3.8'
services:
 db:
   image: postgres:14.1-alpine
   restart: always
   environment:
     - POSTGRES_USER=postgres
     - POSTGRES_PASSWORD=postgres
   ports:
     - '5432:5432'
   volumes:
     - db:/var/lib/postgresql/data
volumes:
 db:
   driver: local

Squelette de schéma de base de données

DROP database confidential_database;
CREATE database confidential_database OWNER "super-application";

CREATE USER "super-application" WITH password 'super-secret-confidentiel';

CREATE TABLE my_secret(name VARCHAR(50));

INSERT INTO my_secret(name) VALUES ('secret-secret!');
INSERT INTO my_secret(name) VALUES ('secret-secret#');

Squelette de l’application

Notre application permet d’accéder à des secrets (stockés en base de données). Son métier est donc "la gestion de secrets".

article-jasypt-2

Secret est notre Entity

@Entity
@Table(name = "my_secret")
public class Secret {
…
}

SecretRepository est notre interface de dépôt.

public interface SecretRepository extends JpaRepository<Secret, String> {
}

SecretService est notre service de récupération de secrets

@Service
public class SecretService implements CommandLineRunner {

   private final static Logger logger = LoggerFactory.getLogger(SecretService.class);

   private final SecretRepository secrets;

   public SecretService(SecretRepository secrets) {
       this.secrets = secrets;
   }

   @Override
   public void run(String... args) throws Exception {
       secrets.findAll().forEach(secret -> logger.info(secret.getName()););
   }
}

Enfin, notre application récupère la configuration dans le fichier credentials.properties

@SpringBootApplication
@PropertySource("credentials.properties")
public class TestingJasyptApplication {
  public static void main(String[] args) {
     SpringApplication.run(TestingJasyptApplication.class, args);
  }
}

Squelette de configuration

Dans le fichier de configuration, ajouter les propriétés de votre instance pour la connexion à la base de données.

spring.datasource.url=jdbc:postgresql://localhost:5432/confidential_database
spring.datasource.username=super-application
spring.datasource.password=super-secret-confidentiel

A ce stade, imaginons une application parfaitement sécurisée qui se connecte à une base de données. Problème ! Malgré tous nos efforts, ses sources, et plus particulièrement le fichier de configuration, ouvrent un accès direct à la base de données.

Nous allons donc utiliser la librairie Jasypt pour remédier au problème.

Activation de JASYPT

Ajouter le starter Spring Boot pour JASYPT dans les dépendances. Ici, on utilise Maven et on ajoute donc la dépendance dans le pom.xml.

<dependency>
   <groupId>com.github.ulisesbocchio</groupId>
   <artifactId>jasypt-spring-boot-starter</artifactId>
   <version>2.0.0</version>
</dependency>

NB. Utiliser la version la plus récente disponible dans le repo central.

A partir de ce moment, comme votre application est annotée @SpringBootApplication, une configuration par défaut de Jasypt est injectée et tous les objets PropertySource contenus dans l'environnement Spring sont prêts à être déchiffrés. Ils doivent simplement respecter la convention par défaut et être entourés par ENC() (Notez que ce pattern est configurable).

Par exemple : ENC(MAVALEURCHFIFREE), où MAVALEURCHIFFREE est la version chiffrée de MAVALEUR.

On peut alors modifier notre fichier de configuration en y indiquant les valeurs chiffrées de nos propriétés à sécuriser, mais avant, nous devons les chiffrer.

Chiffrement de nos propriétés

On peut préparer nos mots de passe directement avec des outils en ligne ou bien, télécharger l’outil CLI de la librairie.

Avec la CLI, lancer la commande suivante :

./encrypt.sh input="super-secret-confidentiel" password="cle-de-chiffrement"

Cela nous donne une chaîne chiffrée en sortie :

EQ+JlJbrbl5xAxr6p9lnXVFwUuNisYS08Vessx6dzlf/5wN/ai6OmQ==

On applique cela à tout, ou partie de, nos propriétés :

spring.datasource.url=ENC(coSkAv+sTpzwK2hzWg0OlutgBsTt9cl+ibvjGxZs6jy5QugWPmc87/BV70IDRHRFrMS8+YKx1gRwtA7EufVECQ==)
spring.datasource.username=ENC(iC4fJHYx6RcLWe6dRYnQxiesyf4ungsZOth/ePhPEIE=)
spring.datasource.password=ENC(EQ+JlJbrbl5xAxr6p9lnXVFwUuNisYS08Vessx6dzlf/5wN/ai6OmQ==)

Ces seules informations ne permettent plus d’avoir accès à la base de données. Rappelez-vous notre fichier initial :

spring.datasource.url=jdbc:postgresql://localhost:5432/confidential_database
spring.datasource.username=super-application
spring.datasource.password=super-secret-confidentiel

Le dernier élément à prendre en compte est la sécurisation de la clé de chiffrement. L’application en a besoin au runtime pour utiliser les mots de passe. Évidemment si on la met dans le fichier de propriétés on retourne au problème initial puisqu’on saura déchiffrer les valeurs. On a donc deux options :

La déployer sur le serveur via une variable d’environnement :

export JASYPT_ENCRYPTOR_PASSWORD=cle-de-chiffrement

L’injecter dans la commande de lancement :

java -Djasypt.encryptor.password="cle-de-chiffrement" mon-application.jar

NB. Si vous avez des tests qui chargent le contexte Spring, il faudra également passer la variable à Maven :

mvn -B clean package -Djasypt.encryptor.password=<secret key>

Conclusion

Grâce à cette librairie simple à mettre en œuvre, on peut monter d'un cran le niveau de sécurité de nos fichiers de configuration. En reprenant notre analogie avec les clés de maison, cela revient à cacher la clé sous le paillasson. C’est pas l’idéal mais c’est déjà beaucoup mieux et, normalement l'assaillant n'a pas les clés de l'immeuble pour avoir accès au paillasson !

Je vous invite à parcourir le repo du starter SpringBoot ainsi que le site de la librairie pour découvrir toutes les possibilités qu’elle offre.

Pour aller plus loin

Voici quelques ressources pour aller plus loin, je vous invite à explorer les éléments suivants :

Bibliographie

Le site de la librairie : jasypt.org
L’adaptateur Spring Boot pour JASYPT : https://github.com/ulisesbocchio/jasypt-spring-boot

Crédits Photos :
Photo by FLY:D on Unsplash