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
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:
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.