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.
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.
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
8. Secure Session Cookie
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á.