1. 概述
H2 控制枱作為 H2 數據庫的圖形用户界面 (GUI) 客户端,允許我們通過網頁查詢數據庫。然而,我們可能會遇到一個問題,即控制枱在 classpath 中存在 Spring Security 依賴時,會顯示空白頁面。
在本教程中,我們將模擬此問題,並通過在 Spring Security 中配置 X-Frame-Options 標頭來解決它。
2. 理解和模擬錯誤
H2 數據庫有助於快速原型設計,因為它共享了大多數生產級 SQL 服務器的特性。但是,在使用 H2 數據庫與 Spring Security 結合時,對 H2 控制枱在瀏覽器中的訪問會自動受到限制。
這是因為 H2 控制枱在 <em>iframe> 中進行渲染,Spring Security 默認會禁用它,以防止諸如點擊劫持之類的網絡攻擊。
在點擊劫持中,惡意網站會在目標網站的框架或按鈕等可點擊元素下嵌入或覆蓋目標網站,欺騙用户與惡意內容交互。安全網站會實施配置以防止內容在框架中渲染。
讓我們通過設置一個簡單的 Spring Boot 項目,其中包含 Spring Security 依賴項來模擬此錯誤。
2.1. Maven 依賴
首先,將 spring-boot-starter-web 和 spring-boot-starter-security 依賴添加到 pom.xml 文件中:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.4.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.4.4</version>
</dependency>spring-boot-starter-web依賴項,包含嵌入式服務器,使我們能夠創建 Web 應用程序。
此外,spring-boot-starter-security依賴項有助於在典型的 Spring Boot 應用程序中驗證和授權端點。當未定義自定義用户詳細信息時,它會在應用程序啓動時默認生成登錄憑據:
- 用户名 – user
- 密碼 – 一個隨機值打印在控制枱中
接下來,讓我們添加 H2 數據庫 依賴項到 pom.xml:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.3.232</version>
</dependency>H2 依賴項提供了一個嵌入式數據庫,非常適合快速原型設計。
2.2. 數據庫配置
接下來,讓我們在 application.properties 文件中配置數據庫連接:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true雖然 Spring Boot 會自動配置數據庫,但我們定義自己的配置來覆蓋默認設置,從而獲得更大的控制權。
默認情況下,spring.h2.console.enable 屬性設置為 false。 我們將其設置為 true 以啓用 H2 Web 控制枱。
2.3. 查看控制枱
啓用 Spring Security 後,包括 “/h2-console/**” 等所有端點默認都需要身份驗證。但是,我們定義一個名為 SecurityConfig 的類來進行自定義配置:
@Configuration
class SecurityConfig {
@Bean
SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.ignoringRequestMatchers("/h2-console/**"))
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated())
.formLogin(withDefaults());
return http.build();
}
}
在上述配置中,我們保留了默認身份驗證和表單登錄行為,但針對“/h2-console/**”啓用了禁用 CSRF 保護,以避免 HTTP 403 錯誤。
接下來,讓我們執行我們的應用程序並檢查 http://localhost:8080/h2-console. 它會將我們重定向到 Spring Security 的登錄頁面,我們使用默認生成的憑據。
登錄後,我們會被重定向到 H2 數據庫登錄頁面:
但是,當我們嘗試登錄時,我們得到一個空白頁面:
這個錯誤是由於 H2 控制枱使用 <iframe> 標籤渲染造成的,Spring Security 默認通過 X-Frame-Options 標頭進行阻止。
3. 通過禁用 X-Frame-Options 修復錯誤
頁面在登錄控制枱後未能加載重要組件。 我們可以通過以下方式解決此問題:要麼禁用 X-Frame-Options 標頭,要麼僅允許來自相同源的幀。
3.1. 全局禁用幀保護,使用 frameOptions()
如果應用程序未 intended 用於生產環境,可以使用 frameOptions() 禁用 X-Frame-Options。
@Bean
SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.ignoringRequestMatchers("/h2-console/**"))
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated())
.formLogin(withDefaults());
return http.build();
}在這裏,我們使用 headers() 方法在 http 實例上,允許幀加載。
讓我們現在查看頁面:
此方法解決了問題,但它在全局級別禁用了 X-Frame-Options。
3.2. 配置同源訪問的Frame選項
雖然之前的解決方案有效,但全局禁用 X-Frame-Options 頭部並不是理想的做法,因為它 暴露了應用程序到潛在的點擊劫持攻擊。相反,我們可以只允許來自相同源的幀訪問:
@Bean
SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.ignoringRequestMatchers("/h2-console/**"))
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin))
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated())
.formLogin(withDefaults());
return http.build();
}在這裏,我們更改了 frameOptions() 以僅允許同源應用程序。
調整此類安全配置,允許僅在同一源內進行幀,可以降低點擊劫持的風險。
4. 結論
在本文中,我們模擬了在瀏覽器中訪問 H2 控制枱時出現的空白頁錯誤,並通過在 Spring Security 中配置 frameOptions() 設置來解決該問題。 此外,我們還了解到如何全局禁用 X-Frame-Options 以供開發用途,並將其限制為同源,從而提高安全性。