知識庫 / Spring / Spring MVC RSS 訂閱

Spring MVC 和 Thymeleaf 中 CSRF 保護

Spring MVC,Spring Security
HongKong
6
02:46 PM · Dec 06 ,2025

1. 簡介

Thymeleaf 是一種 Java 模板引擎,用於處理和創建 HTML、XML、JavaScript、CSS 和純文本。有關 Thymeleaf 和 Spring 的介紹,請參閲此文章。

在本文中,我們將討論如何防止跨站請求偽造 (CSRF) 攻擊在 Spring MVC 中使用 Thymeleaf 應用程序。具體來説,我們將測試 HTTP POST 方法的 CSRF 攻擊。

CSRF 是一種攻擊,強制用户在當前已認證的 Web 應用程序中執行未經授權的操作。

2. Maven 依賴

首先,讓我們看看將 Thymeleaf 與 Spring 集成所需的配置。<em>thymeleaf-spring</em> 庫需要在我們的依賴中:

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>

請注意,對於 Spring 4 項目,必須使用 thymeleaf-spring4 庫,而不是 thymeleaf-spring5 庫。 依賴項的最新版本可以在 這裏找到。

此外,為了使用 Spring Security,我們需要添加以下依賴項:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.7.3</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.7.3</version>
</dependency>

最新版本的兩個與 Spring Security 相關的庫已發佈,可從 這裏這裏 下載。

3. Java 配置

除了此處涵蓋的 Thymeleaf 配置外,還需要添加 Spring Security 的配置。為此,我們需要創建一個類:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebMVCSecurity {

    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user = User.withUsername("user1")
            .password("{noop}user1Pass")
            .authorities("ROLE_USER")
            .build();

        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring()
            .antMatchers("/resources/**");
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic();
        return http.build();
    }
}

對於安全配置的更多詳細信息和描述,請參考“Spring 安全”系列文檔。

默認情況下,通過 Java 配置啓用了 CSRF 保護。 要禁用此有用的功能,需要在 configure(…)方法中添加以下內容:

.csrf().disable()

在XML配置中,我們需要手動指定CSRF保護;否則將無法正常工作:

<security:http 
  auto-config="true"
  disable-url-rewriting="true" 
  use-expressions="true">
    <security:csrf />
     
    <!-- Remaining configuration ... -->
</security:http>

請注意,如果我們在使用帶有包含 PATCH、POST、PUT 或 DELETE 等 HTTP 謂詞的登錄或註銷頁面,並且該頁面包含一個表單,則必須始終在代碼中手動作為隱藏參數包含 CSRF 令牌。

登錄表單中使用 CSRF 令牌的示例:

<form name="login" th:action="@{/login}" method="post"> 
...
<input type="hidden" 
th:name="${_csrf.parameterName}" 
th:value="${_csrf.token}" />
</form>

對於剩餘的表單,如果使用 <em th:action>,則表單中將自動添加 CSRF 令牌。

<input 
  type="hidden" 
  name="_csrf"
  value="32e9ae18-76b9-4330-a8b6-08721283d048" /> 
<!-- Example token -->

4. 視圖配置

讓我們繼續到 HTML 文件中關於表單操作和測試流程創建的主要部分。 在第一個視圖中,我們嘗試將新學生添加到列表中:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org">
<head>
<title>Add Student</title>
</head>
<body>
    <h1>Add Student</h1>
        <form action="#" th:action="@{/saveStudent}" th:object="${student}"
          method="post">
            <ul>
                <li th:errors="*{id}" />
                <li th:errors="*{name}" />
                <li th:errors="*{gender}" />
                <li th:errors="*{percentage}" />
            </ul>
    <!-- Remaining part of HTML -->
    </form>
</body>
</html>

從這個角度來看,我們通過提供 idnamegenderpercentage(如表單驗證中所述,可選)將學生添加到列表中。在執行此表單之前,我們需要提供 userpassword 以在 Web 應用程序中進行身份驗證。

4.1. 瀏覽器 CSRF 攻擊測試

現在我們將轉向第二個 HTML 視圖。其目的是嘗試進行 CSRF 攻擊:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<form action="http://localhost:8080/spring-thymeleaf/saveStudent" method="post">
    <input type="hidden" name="payload" value="CSRF attack!"/>
    <input type="submit" />
</form>
</body>
</html>

我們知道操作 URL 是 http://localhost:8080/spring-thymeleaf/saveStudent。黑客試圖訪問該頁面以執行攻擊。

為了測試,在另一個瀏覽器中打開 HTML 文件,而不登錄應用程序。當您嘗試提交表單時,我們會收到以下頁面:

由於我們發送了缺少 CSRF 令牌的請求,因此我們的請求被拒絕。

請注意,HTTP 會話用於存儲 CSRF 令牌。當請求發送時,Spring 會將生成的令牌與會話中存儲的令牌進行比較,以確認用户未被入侵。

4.2. JUnit CSRF 攻擊測試

如果您不想使用瀏覽器測試 CSRF 攻擊,也可以通過快速集成測試進行,我們先從 Spring 配置開始:

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

    // configuration

}

然後開始進行實際的測試:

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

第一個測試將導致由於缺少 CSRF 令牌而返回禁止狀態,而第二個則會正常執行。

5. 結論

在本文中,我們探討了如何使用 Spring Security 和 Thymeleaf 框架來防止 CSRF 攻擊。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.