Contrôlez la session avec Spring Security

1. Vue d'ensemble

Dans cet article, nous allons illustrer comment Spring Security nous permet de contrôler nos sessions HTTP .

Ce contrôle va d'un délai d'expiration de session à l'activation de sessions simultanées et d'autres configurations de sécurité avancées.

2. Quand la session est-elle créée?

Nous pouvons contrôler exactement quand notre session est créée et comment Spring Security interagira avec elle:

  • always - une session sera toujours créée si elle n'existe pas déjà
  • ifRequired - une session sera créée uniquement si nécessaire ( par défaut )
  • jamais - le framework ne créera jamais de session lui-même mais il en utilisera une s'il existe déjà
  • sans état - aucune session ne sera créée ou utilisée par Spring Security
...

Configuration Java:

@Override protected void configure(HttpSecurity http) throws Exception { http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) }

Il est très important de comprendre que cette configuration ne contrôle que ce que fait Spring Security - pas l'application entière. Spring Security peut ne pas créer la session si nous ne le lui demandons pas, mais notre application peut!

Par défaut, Spring Security créera une session quand il en aura besoin - c'est « ifRequired ».

Pour une application plus sans état , l' option « jamais » garantira que Spring Security lui-même ne créera aucune session; cependant, si l'application en crée un, Spring Security l'utilisera.

Enfin, l'option de création de session la plus stricte - « sans état » - est une garantie que l'application ne créera aucune session du tout .

Cela a été introduit dans Spring 3.1 et ignorera effectivement certaines parties de la chaîne de filtres Spring Security - principalement les parties liées à la session telles que HttpSessionSecurityContextRepository , SessionManagementFilter , RequestCacheFilter .

Ces mécanismes de contrôle plus stricts impliquent directement que les cookies ne sont pas utilisés et que chaque demande doit donc être ré-authentifiée . Cette architecture sans état fonctionne bien avec les API REST et leur contrainte d'apatridie. Ils fonctionnent également bien avec des mécanismes d'authentification tels que l'authentification de base et l'authentification Digest.

3. Sous le capot

Avant d'exécuter le processus d'authentification, Spring Security exécutera un filtre chargé de stocker le contexte de sécurité entre les demandes - le SecurityContextPersistenceFilter . Le contexte sera stocké selon une stratégie - HttpSessionSecurityContextRepository par défaut - qui utilise la session HTTP comme stockage.

Pour l' attribut strict create-session = "stateless" , cette stratégie sera remplacée par une autre - NullSecurityContextRepository - et aucune session ne sera créée ou utilisée pour conserver le contexte.

4. Contrôle de session simultanée

Lorsqu'un utilisateur déjà authentifié tente de s'authentifier à nouveau , l'application peut gérer cet événement de l'une des manières suivantes. Il peut soit invalider la session active de l'utilisateur et authentifier à nouveau l'utilisateur avec une nouvelle session, soit permettre aux deux sessions d'exister simultanément.

La première étape de l'activation de la prise en charge du contrôle de session simultané consiste à ajouter l'écouteur suivant dans le fichier web.xml :

  org.springframework.security.web.session.HttpSessionEventPublisher  

Ou définissez-le comme un Bean - comme suit:

@Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); }

Ceci est essentiel pour vous assurer que le registre de session Spring Security est notifié lorsque la session est détruite .

Pour activer le scénario qui autorise plusieurs sessions simultanées pour le même utilisateur, le L'élément doit être utilisé dans la configuration XML:

Ou, via la configuration Java:

@Override protected void configure(HttpSecurity http) throws Exception { http.sessionManagement().maximumSessions(2) }

5. Délai d'expiration de la session

5.1. Gestion du délai d'expiration de session

Une fois la session expirée , si l'utilisateur envoie une requête avec un identifiant de session expiré , il sera redirigé vers une URL configurable via l'espace de noms:

De même, si l'utilisateur envoie une requête avec un identifiant de session qui n'est pas expiré, mais totalement invalide , il sera également redirigé vers une URL configurable:

 ... 

La configuration Java correspondante:

http.sessionManagement() .expiredUrl("/sessionExpired.html") .invalidSessionUrl("/invalidSession.html");

5.2. Configurer le délai d'expiration de la session avec Spring Boot

Nous pouvons facilement configurer la valeur du délai d'expiration de session du serveur intégré à l'aide des propriétés:

server.servlet.session.timeout=15m

Si nous ne spécifions pas l'unité de durée, Spring supposera qu'il s'agit de secondes.

En un mot, avec cette configuration, après 15 minutes d'inactivité, la session expirera. La session après cette période est considérée comme invalide.

Si nous avons configuré notre projet pour utiliser Tomcat, nous devons garder à l'esprit qu'il ne prend en charge que la précision minute pour le délai d'expiration de la session, avec un minimum d'une minute. Cela signifie que si nous spécifions une valeur de délai d'expiration de 170 s par exemple, cela entraînera un délai d'expiration de 2 minutes.

Enfin, il est important de mentionner que même si Spring Session prend en charge une propriété similaire à cette fin ( spring.session.timeout ), si ce n'est pas spécifié, la configuration automatique reviendra à la valeur de la propriété que nous avons mentionnée en premier.

6. Empêcher l'utilisation des paramètres d'URL pour le suivi de session

L'exposition des informations de session dans l'URL est un risque de sécurité croissant (de la place 7 en 2007 à la place 2 en 2013 sur la liste des 10 meilleurs OWASP).

À partir de Spring 3.0, la logique de réécriture d'URL qui ajouterait le jsessionid à l'URL peut désormais être désactivée en définissant le paramètre disable-url-rewriting = "true" dans le espace de noms.

Alternativement, à partir de Servlet 3.0, le mécanisme de suivi de session peut également être configuré dans le fichier web.xml:

 COOKIE 

Et par programmation:

servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));

Cela choisit où stocker le JSESSIONID - dans le cookie ou dans un paramètre d'URL.

7. Protection contre la fixation de session avec Spring Security

Le cadre offre une protection contre les attaques de fixation de session typiques en configurant ce qui arrive à une session existante lorsque l'utilisateur tente de s'authentifier à nouveau:

 ...

La configuration Java correspondante:

http.sessionManagement() .sessionFixation().migrateSession()

Par défaut, Spring Security a cette protection activée (« migrateSession ») - lors de l'authentification, une nouvelle session HTTP est créée, l'ancienne est invalidée et les attributs de l'ancienne session sont copiés.

Si ce n'est pas le comportement souhaité, deux autres options sont disponibles:

  • lorsque " aucun " est défini, la session d'origine ne sera pas invalidée
  • when “newSession” is set, a clean session will be created without any of the attributes from the old session being copied over

8. Secure Session Cookie

Next, we'll discuss how to secure our session cookie.

We can use the httpOnly and secure flags to secure our session cookie:

  • httpOnly: if true then browser script won't be able to access the cookie
  • secure: if true then the cookie will be sent only over HTTPS connection

We can set those flags for our session cookie in the web.xml:

 1  true true  

This configuration option is available since Java servlet 3. By default, http-only is true and secure is false.

Let's also have a look at the corresponding Java configuration:

public class MainWebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext sc) throws ServletException { // ... sc.getSessionCookieConfig().setHttpOnly(true); sc.getSessionCookieConfig().setSecure(true); } }

If we're using Spring Boot, we can set these flags in our application.properties:

server.servlet.session.cookie.http-only=true server.servlet.session.cookie.secure=true

Finally, we can also achieve this manually by using a Filter:

public class SessionFilter implements Filter { @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; Cookie[] allCookies = req.getCookies(); if (allCookies != null) { Cookie session = Arrays.stream(allCookies).filter(x -> x.getName().equals("JSESSIONID")) .findFirst().orElse(null); if (session != null) { session.setHttpOnly(true); session.setSecure(true); res.addCookie(session); } } chain.doFilter(req, res); } }

9. Working With the Session

9.1. Session Scoped Beans

A bean can be defined with session scope simply by using the @Scope annotation on beans declared in the web-Context:

@Component @Scope("session") public class Foo { .. }

Or with XML:

Then, the bean can simply be injected into another bean:

@Autowired private Foo theFoo;

And Spring will bind the new bean to the lifecycle of the HTTP Session.

9.2. Injecting the Raw Session into a Controller

The raw HTTP Session can also be injected directly into a Controller method:

@RequestMapping(..) public void fooMethod(HttpSession session) { session.setAttribute(Constants.FOO, new Foo()); //... Foo foo = (Foo) session.getAttribute(Constants.FOO); }

9.3. Obtaining the Raw Session

La session HTTP actuelle peut également être obtenue par programme via l' API Servlet brute :

ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpSession session= attr.getRequest().getSession(true); // true == allow create

10. Conclusion

Dans cet article, nous avons discuté de la gestion des sessions avec Spring Security. En outre, la référence Spring contient une très bonne FAQ sur la gestion de session.

Comme toujours, le code présenté dans cet article est disponible à l'adresse over sur Github. Il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.