CSRF-Schutz mit Spring MVC und Thymeleaf

CSRF-Schutz mit Spring MVC und Thymeleaf

1. Einführung

Thymeleaf ist eine Java-Template-Engine zum Verarbeiten und Erstellen von HTML, XML, JavaScript, CSS und Klartext. Ein Intro zu Thymeleaf und Spring finden Sie unterthis writeup.

In diesem Artikel werden wir diskutieren, wieprevent Cross-Site Request Forgery (CSRF) attacks in Spring MVC mit Thymeleaf-Anwendung. Um genauer zu sein, werden wir den CSRF-Angriff für die HTTP-POST-Methode testen.

CSRF ist ein Angriff, der einen Endbenutzer dazu zwingt, unerwünschte Aktionen in einer Webanwendung auszuführen, in der gerade eine Authentifizierung erfolgt.

2. Maven-Abhängigkeiten

Sehen wir uns zunächst die Konfigurationen an, die für die Integration von Thymeleaf in Spring erforderlich sind. Die Bibliothekthymeleaf-springwird in unseren Abhängigkeiten benötigt:


    org.thymeleaf
    thymeleaf
    3.0.9.RELEASE


    org.thymeleaf
    thymeleaf-spring4
    3.0.9.RELEASE

Beachten Sie, dass für ein Spring 4-Projekt die Bibliothekthymeleaf-spring4anstelle vonthymeleaf-spring5verwendet werden muss. Die neueste Version der Abhängigkeiten isthere.

Um Spring Security nutzen zu können, müssen wir außerdem folgende Abhängigkeiten hinzufügen:


    org.springframework.security
    spring-security-web
    5.0.6.RELEASE


    org.springframework.security
    spring-security-config
    5.0.6.RELEASE

Die neuesten Versionen von zwei Spring Security-bezogenen Bibliotheken sindhere undhere verfügbar.

3. Java-Konfiguration

Zusätzlich zur Thymeleaf-Konfiguration, diehere abdeckt, müssen wir die Konfiguration für Spring Security hinzufügen. Dazu müssen wir die Klasse erstellen:

@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();
    }
}

Weitere Einzelheiten und eine Beschreibung der Sicherheitskonfiguration finden Sie in derSecurity with Spring-Serie.

CSRF protection is enabled by default with Java configuration. Um diese nützliche Funktion zu deaktivieren, müssen wir dies inconfigure(…) Methode hinzufügen:

.csrf().disable()

In der XML-Konfiguration müssen wir den CSRF-Schutz manuell festlegen, sonst funktioniert es nicht:


    

    

Bitte beachten Sie auch, dass wir, wenn wir die Anmeldeseite mit Anmeldeformular verwenden, das CSRF-Token im Anmeldeformular immer manuell als versteckten Parameter in den Code einfügen müssen:

Für die übrigen Formulare wird CSRF-Token automatisch zu Formularen mit versteckter Eingabe hinzugefügt:


4. Ansichten Konfiguration

Fahren wir mit dem Hauptteil der HTML-Dateien mit Formularaktionen und der Erstellung von Testverfahren fort. In der ersten Ansicht versuchen wir, einen neuen Schüler zur Liste hinzuzufügen:




Add Student


    

Add Student

In dieser Ansicht fügen wir der Liste einen Schüler hinzu, indem wirid,name,gender undpercentage angeben (optional, wie in der Formularvalidierung angegeben). Bevor wir dieses Formular ausführen können, müssen wiruser undpassword angeben, um uns in einer Webanwendung zu authentifizieren.

4.1. Testen von Browser-CSRF-Angriffen

Nun fahren wir mit der zweiten HTML-Ansicht fort. Der Zweck ist, zu versuchen, einen CSRF-Angriff durchzuführen:




    


Wir wissen, dass die Aktions-URLhttp://localhost:8080/spring-thymeleaf/saveStudent lautet. Der Hacker möchte auf diese Seite zugreifen, um einen Angriff auszuführen.

Öffnen Sie zum Testen die HTML-Datei in einem anderen Browser, ohne sich bei der Anwendung anzumelden. Wenn Sie versuchen, das Formular abzusenden, erhalten wir die Seite:

image

 

Unsere Anfrage wurde abgelehnt, weil wir eine Anfrage ohne CSRF-Token gesendet haben.

Bitte beachten Sie, dass die HTTP-Sitzung zum Speichern des CSRF-Tokens verwendet wird. Wenn die Anforderung gesendet wird, vergleicht Spring das generierte Token mit dem in der Sitzung gespeicherten Token, um zu bestätigen, dass der Benutzer nicht gehackt wurde.

4.2. JUnit CSRF Attack Testing

Wenn Sie CSRF-Angriffe nicht mit einem Browser testen möchten, können Sie dies auch über einen schnellen Integrationstest tun. Beginnen wir mit der Spring-Konfiguration für diesen Test:

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

    // configuration

}

Und weiter zu den eigentlichen Tests:

@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());
}

Der erste Test führt aufgrund des fehlenden CSRF-Tokens zu einem verbotenen Status, während der zweite Test ordnungsgemäß ausgeführt wird.

5. Fazit

In diesem Artikel wurde erläutert, wie CSRF-Angriffe mit Spring Security und Thymeleaf Framework verhindert werden können.

Die vollständige Implementierung dieses Tutorials finden Sie inthe GitHub project - dies ist ein Eclipse-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein.