Kontrollera sessionen med vårsäkerhet

1. Översikt

I den här artikeln ska vi illustrera hur Spring Security tillåter oss att kontrollera våra HTTP-sessioner .

Den här kontrollen sträcker sig från en sessionstimeout till att möjliggöra samtidiga sessioner och andra avancerade säkerhetskonfigurationer.

2. När skapas sessionen?

Vi kan kontrollera exakt när vår session skapas och hur Spring Security kommer att interagera med den:

  • alltid - en session skapas alltid om den inte redan finns
  • ifRequired - en session skapas endast om det krävs ( standard )
  • aldrig - ramverket skapar aldrig en session själv men den kommer att använda en om den redan finns
  • statslös - ingen session skapas eller används av Spring Security
...

Java-konfiguration:

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

Det är mycket viktigt att förstå att den här konfigurationen bara styr vad Spring Security gör - inte hela applikationen. Spring Security kanske inte skapar sessionen om vi instruerar att inte göra det, men vår app kanske!

Som standard skapar Spring Security en session när den behöver en - det här är “ ifRequired ”.

För en mer statslös applikation kommer alternativet “ aldrig ” att säkerställa att Spring Security inte skapar någon session; Men om applikationen skapar en, kommer Spring Security att använda den.

Slutligen är det strängaste alternativet för att skapa session - " statslös " - en garanti för att applikationen inte skapar någon session alls .

Detta infördes under våren 3.1 och kommer effektivt att hoppa över delar av Spring Security-filterkedjan - främst de sessionrelaterade delarna som HttpSessionSecurityContextRepository , SessionManagementFilter , RequestCacheFilter .

Dessa mer strikta kontrollmekanismer har direkt implikation att cookies inte används och så varje begäran måste vara re-verifieras . Denna statslösa arkitektur spelar bra med REST API: er och deras begränsning av statslöshet. De fungerar också bra med autentiseringsmekanismer som Basic och Digest Authentication.

3. Under huven

Innan autentiseringsprocessen körs kommer Spring Security att köra ett filter som ansvarar för lagring av säkerhetskontext mellan förfrågningar - SecurityContextPersistenceFilter . Kontexten lagras enligt en strategi - HttpSessionSecurityContextRepository som standard - som använder HTTP-sessionen som lagring.

För attributet strikt create-session = ”stateless” kommer denna strategi att ersättas med en annan - NullSecurityContextRepository - och ingen session kommer att skapas eller användas för att behålla sammanhanget.

4. Samtidig sessionskontroll

När en användare som redan är autentiserad försöker autentisera igen kan applikationen hantera den händelsen på ett av få sätt. Det kan antingen ogiltiga användarens aktiva session och autentisera användaren igen med en ny session eller låta båda sessionerna existera samtidigt.

Det första steget i att aktivera stödet för samtidig sessionskontroll är att lägga till följande lyssnare på web.xml :

  org.springframework.security.web.session.HttpSessionEventPublisher  

Eller definiera det som en böna - enligt följande:

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

Detta är viktigt för att säkerställa att Spring Security-sessionsregistret meddelas när sessionen förstörs .

För att aktivera scenariot som tillåter flera samtidiga sessioner för samma användare elementet ska användas i XML-konfigurationen:

Eller via Java-konfiguration:

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

5. Sessionstimeout

5.1. Hantering av sessionens timeout

Om användaren skickar en begäran med ett utgångt session-ID efter att timen har gått ut , kommer de att omdirigeras till en URL som kan konfigureras via namnområdet:

På samma sätt, om användaren skickar en begäran med ett sessions-id som inte är utgånget men helt ogiltigt , kommer de också att omdirigeras till en konfigurerbar URL:

 ... 

Motsvarande Java-konfiguration:

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

5.2. Konfigurera Session Timeout med Spring Boot

Vi kan enkelt konfigurera Session timeout-värdet för den inbäddade servern med hjälp av egenskaper:

server.servlet.session.timeout=15m

Om vi ​​inte anger varaktighetsenheten antar Spring att det är sekunder.

I ett nötskal, med den här konfigurationen, kommer sessionen att gå ut efter 15 minuters inaktivitet. Sessionen efter denna tidsperiod anses vara ogiltig.

Om vi ​​konfigurerade vårt projekt att använda Tomcat måste vi komma ihåg att det bara stöder minutprecision för sessionstimeout, med minst en minut. Detta innebär att om vi till exempel anger ett timeoutvärde på 170s , kommer det att resultera i en 2-minuters timeout.

Slutligen är det viktigt att nämna att även om Spring Session stöder en liknande egenskap för detta ändamål ( spring.session.timeout ), om det inte anges så kommer autokonfigurationen att falla tillbaka till värdet på egenskapen vi först nämnde.

6. Förhindra att URL-parametrar används för sessionsspårning

Att exponera sessionsinformation i URL: en är en växande säkerhetsrisk (från plats 7 2007 till plats 2 2013 på OWASPs topp 10-lista).

Från och med våren 3.0 kan logiken för omskrivning av URL som skulle lägga till jsessionid till URL: n inaktiveras genom att ställa in disable-url-rewriting = ”true” i namnområde.

Alternativt, från och med Servlet 3.0, kan sessionsspårningsmekanismen också konfigureras på web.xml:

 COOKIE 

Och programmatiskt:

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

Detta väljer var JSESSIONID ska sparas - i cookien eller i en URL-parameter.

7. Sessionsfixeringsskydd med vårsäkerhet

Ramverket erbjuder skydd mot typiska Session Fixation-attacker genom att konfigurera vad som händer med en befintlig session när användaren försöker autentisera igen:

 ...

Motsvarande Java-konfiguration:

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

Som standard har Spring Security detta skydd aktiverat (“ migrateSession ”) - vid autentisering skapas en ny HTTP-session, den gamla ogiltigförklaras och attributen från den gamla sessionen kopieras över.

Om detta inte är det önskade beteendet finns två andra alternativ tillgängliga:

  • när “ ingen ” är inställd, ogiltigförklaras inte den ursprungliga sessionen
  • 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

Den aktuella HTTP-sessionen kan också erhållas programmatiskt via Raw Servlet API :

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

10. Slutsats

I den här artikeln diskuterade vi hantering av sessioner med vårsäkerhet. Vårreferensen innehåller också en mycket bra FAQ om sessionshantering.

Som alltid finns koden i den här artikeln tillgänglig på Github. Detta är ett Maven-baserat projekt, så det borde vara enkelt att importera och köra som det är.