Controlar a sessão com Spring Security

Controlar a sessão com Spring Security

1. Visão geral

Neste artigo, vamos ilustrar comoSpring Security allows us to control our HTTP Sessions.

Esse controle varia de um tempo limite de sessão a habilitar sessões simultâneas e outras configurações de segurança avançadas.

Leitura adicional:

Recuperar informações do usuário no Spring Security

Como obter o usuário conectado no momento com o Spring Security.

Read more

Spring Security Lembre-se de mim

Exemplo de Cookie Remember Me com Spring Security.

Read more

Spring Security Logout

Exemplo de logout de primavera - como configurar o URL de logout, o logout-succcess-url e como usar um bean personalizado para lidar com cenários avançados de logout.

Read more

2. Quando a sessão é criada?

Podemos controlar exatamente quando nossa sessão é criada e como o Spring Security irá interagir com ela:

  • always - uma sessão sempre será criada se ainda não houver uma

  • ifRequired - uma sessão será criada apenas se necessário (default)

  • never - o framework nunca criará uma sessão por si só, mas usará uma se já existir

  • stateless - nenhuma sessão será criada ou usada pelo Spring Security

...

Configuração Java:

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

É muito importante entender quethis configuration only controls what Spring Security does - não o aplicativo inteiro. O Spring Security pode não criar a sessão se instruirmos, mas nosso aplicativo pode!

Por padrão,Spring Security will create a session when it needs one - este é “ifRequired“.

Paraa more stateless application, a opção “never” garantirá que o Spring Security em si não criará nenhuma sessão; entretanto, se o aplicativo criar um, o Spring Security fará uso dele.

Finalmente, a opção de criação de sessão mais restrita - “stateless” - éguarantee that the application will not create any session at all.

Isso eraintroduced no Spring 3.1 e pulará efetivamente partes da cadeia de filtros do Spring Security - principalmente as partes relacionadas à sessão, comoHttpSessionSecurityContextRepository,SessionManagementFilter,RequestCacheFilter.

Esses mecanismos de controle mais estritos têm a implicação direta de quecookies are not usedeeach and every request needs to be re-authenticated. Essa arquitetura sem estado funciona bem com APIs REST e suas restrições de estado sem estado. Eles também funcionam bem com mecanismos de autenticação, como Autenticação básica e Digest.

3. Sob o capô

Antes de executar o processo de autenticação, Spring Security executará um filtro responsável por armazenar o Contexto de Segurança entre as solicitações - oSecurityContextPersistenceFilter. O contexto será armazenado de acordo com uma estratégia -HttpSessionSecurityContextRepository por padrão - que usa a Sessão HTTP como armazenamento.

Para o atributo estritocreate-session=”stateless”, esta estratégia será substituída por outra -NullSecurityContextRepository - eno session will be created or used para manter o contexto.

4. Controle de sessão simultânea

Quando um usuário que já está autenticado tentaauthenticate again, o aplicativo pode lidar com esse evento de algumas maneiras. Ele pode invalidar a sessão ativa do usuário e autenticá-lo novamente com uma nova sessão ou permitir que ambas as sessões existam simultaneamente.

A primeira etapa para ativar o suportesession-control simultâneo é adicionar o seguinte ouvinte emweb.xml:


    
      org.springframework.security.web.session.HttpSessionEventPublisher
    

Ou defina-o como um Bean - da seguinte maneira:

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

Isso é essencial para garantir que o registro da sessão do Spring Security sejanotified when the session is destroyed.

Para ativar o cenário que permite várias sessões simultâneas para o mesmo usuário, o elemento<session-management> deve ser usado na configuração XML:


    
        
    

Ou, via configuração Java:

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

5. Sessão expirada

5.1. Lidando com o tempo limite da sessão

Depois que a sessão expirou, se o usuário enviar uma solicitação comexpired session id, ele será redirecionado para um URL configurável por meio do namespace:


    

Da mesma forma, se o usuário enviar uma solicitação com um id de sessão que não expirou, mas totalmenteinvalid, ele também será redirecionado para um URL configurável:


    ...

A configuração Java correspondente:

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

5.2. Configurar o tempo limite da sessão com boot inicial

Podemos configurar facilmente o valor do tempo limite da sessão do servidor incorporado usando as propriedades:

server.servlet.session.timeout=15m

Se não especificarmos a unidade de duração, Spring assumirá que são segundos.

Em poucas palavras, com essa configuração, após 15 minutos de inatividade, a sessão expirará. A sessão após esse período é considerada inválida.

Se configuramos nosso projeto para usar o Tomcat, devemos ter em mente que ele suporta apenas precisão de minutos para o tempo limite da sessão, com no mínimo um minuto. Isso significa que se especificarmos um valor de tempo limite de170s, por exemplo, isso resultará em um tempo limite de 2 minutos.

Finalmente, é importante mencionar que, emboraSpring Session suporte uma propriedade semelhante para esta finalidade (spring.session.timeout), se isso não for especificado, a configuração automática voltará ao valor da propriedade que mencionamos primeiro.

6. Impedir o uso de parâmetros de URL para rastreamento de sessão

A exposição de informações da sessão no URL é um crescimentosecurity risk (do lugar 7 em 2007 para o lugar 2 em 2013 na lista dos 10 principais OWASP).

Starting with Spring 3.0, a lógica de reescrita de URL que acrescentariajsessionid à URL agora pode ser desabilitada definindodisable-url-rewriting=”true” no namespace<http>.

Alternativamente, começando com Servlet 3.0, o mecanismo de rastreamento de sessão também pode ser configurado noweb.xml:


     COOKIE

E programaticamente:

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

Isso escolhe onde armazenar oJSESSIONID - no cookie ou em um parâmetro de URL.

7. Proteção de fixação de sessão com Spring Security

A estrutura oferece proteção contra ataques típicos de fixação de sessão, configurando o que acontece com uma sessão existente quando o usuário tenta se autenticar novamente:

 ...

A configuração Java correspondente:

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

Por padrão, Spring Security tem essa proteção habilitada (“migrateSession“) - na autenticação, uma nova Sessão HTTP é criada, a antiga é invalidada e os atributos da sessão antiga são copiados.

Se esse não for o comportamento desejado, outras duas opções estarão disponíveis:

  • quando “none” é definido, a sessão original não será invalidada

  • quando “newSession” é definido, uma sessão limpa será criada sem nenhum dos atributos da sessão antiga sendo copiado

A seguir, discutiremos como proteger nosso cookie de sessão.

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

  • httpOnly: se verdadeiro, o script do navegador não será capaz de acessar o cookie

  • secure: se verdadeiro, o cookie será enviado apenas por conexão HTTPS

Podemos definir esses sinalizadores para nosso cookie de sessão noweb.xml:


    1
    
        true
        true
    

Esta opção de configuração está disponível desde o servlet Java 3. Por padrão,http-only é verdadeiro esecure é falso.

Vamos também dar uma olhada na configuração Java correspondente:

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

Finalmente, também podemos fazer isso manualmente usando umFilter:

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. Trabalhando com a Sessão

9.1. Beans com escopo de sessão

Um bean pode ser definido com o escoposession simplesmente usando a anotação @Scope nos beans declarados no contexto da web:

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

Ou com XML:

Então, o feijão pode simplesmente ser injetado em outro feijão:

@Autowired
private Foo theFoo;

E o Spring vinculará o novo bean ao ciclo de vida da sessão HTTP.

9.2. Injetando a sessão bruta em um controlador

A sessão HTTP bruta também pode ser injetada diretamente em um métodoController:

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

9.3. Obtendo a Sessão Bruta

A sessão HTTP atual também pode ser obtida programaticamente por meio doraw Servlet API:

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

10. Conclusão

Neste artigo, discutimos o gerenciamento de sessões com o Spring Security. Além disso, o Spring Reference contém um bomFAQ on Session Management.

Como sempre, o código apresentado neste artigo está disponívelover on Github. Este é um projeto baseado em Maven, portanto, deve ser fácil importar e executar como está.