Précédemment, vous avez pu suivre le tutoriel suivant qui explique comment créer et exposer une API REST rapidement grâce à Spring Boot:
Et avez ainsi créé une première API.
Cette fois, nous allons aborder un aspect essentiel de toute API : sa sécurisation. En effet, sans mesures de sécurité adéquates, vos données peuvent être exposées à des accès non autorisés ou des attaques malveillantes.
Dans cette série d'articles, nous verrons comment sécuriser une API avec Spring Security et différentes méthodes d’authentification, ici il s'agira de Basic Auth.
Pourquoi sécuriser une API ?
Une API REST est souvent le point d’entrée des données sensibles de votre application. Si elle n’est pas protégée, elle devient vulnérable à :
- L’accès non autorisé.
- Les attaques comme le man-in-the-middle, brute force ou injection.
- La divulgation de données sensibles.
Définition de Basic Auth
Basic Auth (ou Basic Authentication) est une méthode simple d'authentification HTTP où le client (comme un navigateur ou une application) transmet des informations d'identification (nom d'utilisateur et mot de passe) au serveur dans chaque requête.
Ces informations sont encodées en Base64 et envoyées dans l'en-tête HTTP Authorization
. L'encodage Base64 ne fournit aucune sécurité réelle, il s'agit simplement d'un format d'encodage lisible, et non de chiffrement. Voici un exemple d'en-tête HTTP utilisant Basic Auth :
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Dans cet exemple :
dXNlcm5hbWU6cGFzc3dvcmQ=
est l'encodage Base64 deusername:password
.
Cas pratique : Ajouter Spring Security
Ajoutez les dépendances suivantes de Spring Security dans votre fichier pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Pour les tests -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
Notre API à sécuriser
Pour cet exemple, nous allons rester simple, nous allons avoir une API avec 2 points d'entrée :
@RestController
public class HelloController {
@GetMapping("/hello")
public String sayHello() {
return "Hello world!";
}
@GetMapping("/goodbye")
public String sayGoodbye() {
return "GoodBye world!";
}
}
Le premier /hello
retournera la chaine de caractères "Hello World!" et le second /goodbye
retournera quant à lui "GoodBye world!"
Comportement par défaut
Par défaut, à partir du moment où vous avez rajouté la dépendance de spring-security, vous n'avez déjà plus accès librement à vos API.
En effet si j'exécute la requête suivante http://localhost:8083/hello via Postman / Bruno ou n'importe quels autres outils de requêtage le système me renverra un code retour HTTP 401.
Mais alors, comment tester le résultat de ma requête ?
La sécurité par défaut qui est mise en place lors de l'ajout de la dépendance est le Basic Auth, avec comme username par défaut user et un mot de passe généré aléatoirement que vous pouvez trouver dans les logs de votre application au démarrage de cette dernière avec un petit message d'avertissement.
Using generated security password: 2849f6e7-4406-45fb-ae3c-0b8a091d499b
This generated password is for development use only. Your security configuration must be updated before running your application in production.
Configurer l’authentification avec Basic Auth
Une méthode simple pour sécuriser une API est d'utiliser Basic Auth, où chaque requête contient un en-tête avec un nom d’utilisateur et un mot de passe encodés en base 64.
Créez une classe SecurityConfig
:
Analysons de plus près ce que fait cette classe
securityFilterChain
Cette méthode configure le SecurityFilterChain, qui est une chaîne de filtres définissant les règles de sécurité pour gérer les requêtes HTTP.
Détails de la configuration :
- Désactivation de CSRF :
.csrf(AbstractHttpConfigurer::disable)
Le mécanisme CSRF (Cross-Site Request Forgery) est désactivé ici. Ce mécanisme est utile pour les applications web avec sessions, mais souvent inutile pour les API REST.
- Règles d'autorisation des requêtes :
.authorizeHttpRequests(auth ->
auth.requestMatchers("/goodbye").permitAll()
.anyRequest().authenticated())
- Les requêtes vers le chemin
/goodbye
sont publiques et ne nécessitent pas d'authentification (permitAll()
). - Toutes les autres requêtes (
anyRequest()
) nécessitent que l'utilisateur soit authentifié (authenticated()
). - Utilisation de Basic Auth :
.httpBasic(Customizer.withDefaults())
Cela active l'authentification Basic Auth, qui demande des identifiants (nom d'utilisateur et mot de passe) dans chaque requête via l'en-tête HTTP Authorization
.
UserDetailService
Le UserDetailsService
est une interface de Spring Security utilisée pour récupérer les détails des utilisateurs nécessaires à l'authentification et à l'autorisation.
Il joue un rôle central dans la gestion de la sécurité de l'application.
Cette interface ne contient qu'une seule méthode
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
- Cette méthode est appelée par Spring Security pour récupérer les informations d'un utilisateur donné (en fonction de son nom d'utilisateur).
- Les informations retournées sont encapsulées dans un objet
UserDetails
, qui contient des détails sur l'utilisateur, comme :- Nom d'utilisateur
- Mot de passe
- Rôles/autorités
- État actif ou inactif de l'utilisateur
Dans notre exemple, mes utilisateurs sont enregistrés dans un gestionnaire en mémoire (InMemoryUserDetailsManager
).
C'est une implémentation simple qui ne nécessite pas de base de données, idéal pour des démo ou des tests.
Pour des applications réelles, les utilisateurs sont souvent stockés dans une base de données. et il vous reviendra donc la charge d'implémenter votre propre UserDetailService.
Pour résumer
Nous avons configuré la sécurité de notre application de la façon suivante :
- Les requêtes vers le chemin
/goodbye
sont publiques et ne nécessitent pas d'authentification. - Toutes les autres requêtes nécessitent que l'utilisateur soit authentifié.
Pour conclure
Dans cet article, nous avons vu comment sécuriser une API REST avec Spring Security en utilisant Basic Auth. Cette méthode, bien que simple à mettre en œuvre, constitue une première étape pour protéger vos points d'entrée contre les accès non autorisés.
Cette configuration est idéale pour démarrer, mais dans une application en production, plusieurs améliorations doivent être envisagées, telles que :
- L'utilisation d'une base de données pour stocker les utilisateurs et leurs rôles.
- La mise en place d'un chiffrement HTTPS pour protéger les données échangées.
- Le remplacement de Basic Auth par des mécanismes plus sécurisés comme OAuth2 ou JWT.
En sécurisant votre API, vous assurez non seulement la confidentialité et l'intégrité de vos données, mais vous renforcez également la confiance des utilisateurs dans votre application.
Dans les prochains articles, nous explorerons d'autres méthodes d'authentification et verrons comment adapter Spring Security à des scénarios plus avancés.
Tout le code relatif à cet article est trouvable ici :
Pour les besoins de l'article, les mots de passe ont été commit en clair, mais évidemment vous savez que ce n'est pas une bonne pratique.