Beheer de sessie met Spring Security

1. Overzicht

In dit artikel laten we zien hoe Spring Security stelt ons in staat om onze HTTP-sessies te beheren.

Deze controle varieert van een sessietime-out tot het inschakelen van gelijktijdige sessies en andere geavanceerde beveiligingsconfiguraties.

2. Wanneer wordt de sessie gemaakt?

We kunnen precies bepalen wanneer onze sessie wordt gemaakt en hoe Spring Security ermee zal omgaan:

  • altijd- er wordt altijd een sessie aangemaakt als deze nog niet bestaat
  • indien nodig- er wordt alleen een sessie aangemaakt als dat nodig is (standaard)
  • nooit- het framework zal zelf nooit een sessie maken, maar het zal er een gebruiken als deze al bestaat
  • staatloos- er wordt geen sessie aangemaakt of gebruikt door Spring Security
...

Java-configuratie:

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

Het is erg belangrijk om dat te begrijpen deze configuratie bepaalt alleen wat Spring Security doet - niet de hele applicatie. Spring Security maakt de sessie mogelijk niet als we hem instrueren om dit niet te doen, maar onze app wel!

Standaard, Spring Security zal een sessie aanmaken wanneer dat nodig is - dit is "indien nodig“.

Voor een meer staatloze applicatie, de "nooit”Optie zorgt ervoor dat Spring Security zelf geen sessie aanmaakt; Als de applicatie er echter een aanmaakt, zal Spring Security er gebruik van maken.

Eindelijk, de meest strikte optie voor het maken van sessies: "staatloos" - is een garanderen dat de applicatie helemaal geen sessie zal creëren.

Dit werd geïntroduceerd in Spring 3.1 en zal effectief delen van de Spring Security-filterketen overslaan - voornamelijk de sessiegerelateerde delen zoals HttpSessionSecurityContextRepository, SessionManagementFilter, RequestCacheFilter.

Deze strengere controlemechanismen hebben de directe implicatie dat cookies worden niet gebruikt en dus elk verzoek moet opnieuw worden geauthenticeerd. Deze staatloze architectuur speelt goed met REST API's en hun staatloosheidsbeperking. Ze werken ook goed met authenticatiemechanismen zoals Basic en Digest Authentication.

3. Onder de motorkap

Voordat het verificatieproces wordt uitgevoerd, voert Spring Security een filter uit dat verantwoordelijk is voor het opslaan van de beveiligingscontext tussen verzoeken - het SecurityContextPersistenceFilter. De context wordt opgeslagen volgens een strategie - HttpSessionSecurityContextRepository standaard - die de HTTP-sessie als opslag gebruikt.

Voor de strikte create-session = "staatloos" attribuut, zal deze strategie worden vervangen door een ander - NullSecurityContextRepository - en er wordt geen sessie gemaakt of gebruikt om de context te behouden.

4. Gelijktijdige sessiecontrole

Wanneer een gebruiker die al is geverifieerd, dit probeert authenticeer opnieuw, kan de applicatie die gebeurtenis op een van de volgende manieren afhandelen. Het kan de actieve sessie van de gebruiker ongeldig maken en de gebruiker opnieuw verifiëren met een nieuwe sessie, of beide sessies gelijktijdig laten bestaan.

De eerste stap bij het inschakelen van het concurrent sessie-controle ondersteuning is om de volgende luisteraar toe te voegen in het web.xml:

  org.springframework.security.web.session.HttpSessionEventPublisher 

Of definieer het als een boon - als volgt:

@Bean openbare HttpSessionEventPublisher httpSessionEventPublisher () {retourneer nieuwe HttpSessionEventPublisher (); }

Dit is essentieel om ervoor te zorgen dat het Spring Security-sessieregistratie op de hoogte gebracht wanneer de sessie wordt vernietigd.

Om het scenario in te schakelen dat meerdere gelijktijdige sessies voor dezelfde gebruiker toestaat, moet het element moet worden gebruikt in de XML-configuratie:

Of, via Java-configuratie:

@Override protected void configure (HttpSecurity http) genereert uitzondering {http.sessionManagement (). MaximumSessions (2)}

5. Time-out sessie

5.1. Omgaan met de sessietime-out

Nadat de sessie is verlopen en de gebruiker een verzoek verzendt met een verlopen sessie-ID, worden ze omgeleid naar een URL die kan worden geconfigureerd via de naamruimte:

Evenzo als de gebruiker een verzoek verzendt met een sessie-ID dat niet is verlopen, maar volledig ongeldig, worden ze ook omgeleid naar een configureerbare URL:

 ... 

De bijbehorende Java-configuratie:

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

5.2. Configureer de sessietime-out met Spring Boot

We kunnen de sessietime-outwaarde van de ingesloten server eenvoudig configureren met behulp van eigenschappen:

server.servlet.session.timeout = 15m

Als we de duureenheid niet specificeren, gaat Spring ervan uit dat het seconden is.

Kortom, met deze configuratie vervalt de sessie na 15 minuten inactiviteit. De sessie na deze periode wordt als ongeldig beschouwd.

Als we ons project hebben geconfigureerd om Tomcat te gebruiken, moeten we in gedachten houden dat het alleen minuutprecisie ondersteunt voor sessietime-out, met een minimum van één minuut. Dit betekent dat als we een time-outwaarde specificeren van 170s Het zal bijvoorbeeld resulteren in een time-out van 2 minuten.

Ten slotte is het belangrijk om te vermelden dat, hoewel Spring Session een vergelijkbare eigenschap voor dit doel ondersteunt (spring.session.time-out), als dat niet is opgegeven, valt de autoconfiguratie terug op de waarde van de eigenschap die we het eerst noemden.

6. Voorkom het gebruik van URL-parameters voor het bijhouden van sessies

Het vrijgeven van sessie-informatie in de URL is een groeiend beveiligingsrisico (van plaats 7 in 2007 naar plaats 2 in 2013 op de OWASP Top 10-lijst).

Beginnend met Spring 3.0, de logica voor het herschrijven van URL's waaraan de jsessionid naar de URL kan nu worden uitgeschakeld door de disable-url-rewriting = "true" in de naamruimte.

Als alternatief, te beginnen met Servlet 3.0, kan het sessie-volgmechanisme ook worden geconfigureerd in het web.xml:

 KOEKJE 

En programmatisch:

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

Dit bepaalt waar het JSESSIONID - in de cookie of in een URL-parameter.

7. Sessiefixatiebescherming met veerbeveiliging

Het framework biedt bescherming tegen typische Session Fixation-aanvallen door te configureren wat er met een bestaande sessie gebeurt wanneer de gebruiker opnieuw probeert te authenticeren:

 ...

De bijbehorende Java-configuratie:

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

Spring Security heeft deze bescherming standaard ingeschakeld ("migrateSession“) - bij authenticatie wordt een nieuwe HTTP-sessie aangemaakt, de oude wordt ongeldig gemaakt en de attributen van de oude sessie worden gekopieerd.

Als dit niet het gewenste gedrag is, zijn er twee andere opties:

  • wanneer "geen”Is ingesteld, wordt de oorspronkelijke sessie niet ongeldig gemaakt
  • wanneer "newSession”Is ingesteld, wordt er een schone sessie gemaakt zonder dat de attributen van de oude sessie worden gekopieerd

8. Veilige sessiecookie

Vervolgens bespreken we hoe u onze sessiecookie kunt beveiligen.

We kunnen de httpAlleen en veilig vlaggen om onze sessiecookie te beveiligen:

  • httpAlleen: indien waar dan heeft het browserscript geen toegang tot de cookie
  • beveiligen: indien waar, wordt de cookie alleen via HTTPS-verbinding verzonden

We kunnen die vlaggen voor onze sessiecookie instellen in het web.xml:

 1 waar waar 

Deze configuratieoptie is beschikbaar sinds Java-servlet 3. Standaard alleen http is waar en veilig is fout.

Laten we ook eens kijken naar de bijbehorende Java-configuratie:

openbare klasse MainWebAppInitializer implementeert WebApplicationInitializer {@Override public void onStartup (ServletContext sc) gooit ServletException {// ... sc.getSessionCookieConfig (). setHttpOnly (true); sc.getSessionCookieConfig (). setSecure (true); }}

Als we Spring Boot gebruiken, kunnen we deze vlaggen in onze application.properties:

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

Ten slotte kunnen we dit ook handmatig doen door een Filter:

openbare klasse SessionFilter implementeert Filter {@Override public void doFilter (ServletRequest-verzoek, ServletResponse-antwoord, FilterChain-keten) gooit IOException, ServletException {HttpServletRequest req = (HttpServletRequest) -verzoek; HttpServletResponse res = (HttpServletResponse) antwoord; Cookie [] allCookies = req.getCookies (); if (allCookies! = null) {Cookie sessie = Arrays.stream (allCookies) .filter (x -> x.getName (). equals ("JSESSIONID")) .findFirst (). orElse (null); if (sessie! = null) {session.setHttpOnly (true); session.setSecure (true); res.addCookie (sessie); }} chain.doFilter (req, res); }}

9. Werken met de sessie

9.1. Session Scoped Beans

Een boon kan worden gedefinieerd met sessie bereik eenvoudig door de @Scope-annotatie te gebruiken op bonen die zijn gedeclareerd in de webcontext:

@Component @Scope ("sessie") openbare klasse Foo {..}

Of met XML:

Vervolgens kan de boon eenvoudig in een andere boon worden geïnjecteerd:

@Autowired privé Foo theFoo;

En Spring zal de nieuwe bean binden aan de levenscyclus van de HTTP-sessie.

9.2. De onbewerkte sessie in een controller injecteren

De onbewerkte HTTP-sessie kan ook rechtstreeks in een Controller methode:

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

9.3. Verkrijgen van de Raw-sessie

De huidige HTTP-sessie kan ook programmatisch worden verkregen via het onbewerkte Servlet API:

ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes (); HttpSession-sessie = attr.getRequest (). GetSession (true); // true == create

10. Conclusie

In dit artikel hebben we het gehad over het beheren van sessies met Spring Security. Ook bevat de Spring Reference een zeer goede FAQ over sessiebeheer.

Zoals altijd is de code die in dit artikel wordt gepresenteerd, beschikbaar op Github. Dit is een op Maven gebaseerd project, dus het zou gemakkelijk moeten kunnen worden geïmporteerd en uitgevoerd zoals het is.