Protezione CSRF con Spring MVC e Thymeleaf

1. Introduzione

Thymeleaf è un motore di modelli Java per l'elaborazione e la creazione di HTML, XML, JavaScript, CSS e testo in chiaro. Per un'introduzione a Thymeleaf e Spring, dai un'occhiata a questo articolo.

In questo articolo, discuteremo come prevenire attacchi CSRF (Cross-Site Request Forgery) in Spring MVC con l'applicazione Thymeleaf. Per essere più specifici, testeremo l'attacco CSRF per il metodo HTTP POST.

CSRF è un attacco che costringe un utente finale a eseguire azioni indesiderate in un'applicazione web in cui è attualmente autenticato.

2. Dipendenze di Maven

Innanzitutto, vediamo le configurazioni richieste per integrare Thymeleaf con Spring. La libreria thymeleaf-spring è richiesta nelle nostre dipendenze:

 org.thymeleaf thymeleaf 3.0.11.RELEASE   org.thymeleaf thymeleaf-spring5 3.0.11.RELEASE 

Nota che, per un progetto Spring 4, la libreria thymeleaf-spring4 deve essere utilizzata al posto di thymeleaf-spring5 . L'ultima versione delle dipendenze può essere trovata qui.

Inoltre, per poter utilizzare Spring Security, dobbiamo aggiungere le seguenti dipendenze:

 org.springframework.security spring-security-web 5.2.3.RELEASE   org.springframework.security spring-security-config 5.2.3.RELEASE  

Le ultime versioni di due librerie relative a Spring Security sono disponibili qui e qui.

3. Configurazione Java

Oltre alla configurazione Thymeleaf trattata qui, è necessario aggiungere la configurazione per Spring Security. Per fare ciò, dobbiamo creare la classe:

@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class WebMVCSecurity extends WebSecurityConfigurerAdapter { @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user1").password("{noop}user1Pass") .authorities("ROLE_USER"); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/resources/**"); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest() .authenticated() .and() .httpBasic(); } }

Per maggiori dettagli e descrizione della configurazione della sicurezza, fare riferimento alla serie Security with Spring.

La protezione CSRF è abilitata per impostazione predefinita con la configurazione Java. Per disabilitare questa utile funzione dobbiamo aggiungerla nel metodo configure (...) :

.csrf().disable()

Nella configurazione XML dobbiamo specificare manualmente la protezione CSRF, altrimenti non funzionerà:

Si noti inoltre che se si utilizza la pagina di accesso con il modulo di accesso, è necessario includere sempre il token CSRF nel modulo di accesso come parametro nascosto manualmente nel codice:

Per i moduli rimanenti, il token CSRF verrà automaticamente aggiunto ai moduli con input nascosto:

4. Configurazione delle viste

Passiamo alla parte principale dei file HTML con le azioni del modulo e la creazione della procedura di test. Nella prima visualizzazione, proviamo ad aggiungere un nuovo studente all'elenco:

   Add Student   
    

In questa visualizzazione, stiamo aggiungendo uno studente all'elenco, fornendo ID , nome , sesso e percentuale (facoltativamente, come indicato nella convalida del modulo). Prima di poter eseguire questo modulo, dobbiamo fornire utente e password , per autenticarci in un'applicazione web.

4.1. Browser CSRF Attack Testing

Ora procediamo alla seconda visualizzazione HTML. Lo scopo è provare a eseguire un attacco CSRF:

Sappiamo che l'URL dell'azione è // localhost: 8080 / spring-thymeleaf / saveStudent . L'hacker vuole accedere a questa pagina per eseguire un attacco.

Per eseguire il test, apri il file HTML in un altro browser, senza accedere all'applicazione. Quando proverai a inviare il modulo, riceveremo la pagina:

La nostra richiesta è stata rifiutata perché abbiamo inviato una richiesta senza un token CSRF.

Si noti che la sessione HTTP viene utilizzata per memorizzare il token CSRF. Quando la richiesta viene inviata, Spring confronta il token generato con il token memorizzato nella sessione, al fine di confermare che l'utente non è stato violato.

4.2. JUnit CSRF Attack Testing

Se non vuoi testare l'attacco CSRF utilizzando un browser, puoi farlo anche tramite un rapido test di integrazione; iniziamo con la configurazione Spring per quel test:

@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = { WebApp.class, WebMVCConfig.class, WebMVCSecurity.class, InitSecurity.class }) public class CsrfEnabledIntegrationTest { // configuration }

E passa ai test effettivi:

@Test public void addStudentWithoutCSRF() throws Exception { mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON) .param("id", "1234567").param("name", "Joe").param("gender", "M") .with(testUser())).andExpect(status().isForbidden()); } @Test public void addStudentWithCSRF() throws Exception { mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON) .param("id", "1234567").param("name", "Joe").param("gender", "M") .with(testUser()).with(csrf())).andExpect(status().isOk()); }

Il primo test risulterà in uno stato proibito a causa del token CSRF mancante, mentre il secondo verrà eseguito correttamente.

5. conclusione

In questo articolo, abbiamo discusso come prevenire gli attacchi CSRF utilizzando Spring Security e il framework Thymeleaf.

L'implementazione completa di questo tutorial può essere trovata nel progetto GitHub: questo è un progetto basato su Eclipse, quindi dovrebbe essere facile da importare ed eseguire così com'è.