セキュリティ HTTP レスポンスヘッダー

セキュリティ HTTP レスポンスヘッダーを使用して、Web アプリケーションのセキュリティを強化できます。このセクションでは、セキュリティ HTTP レスポンスヘッダーのサーブレットベースのサポートについて説明します。

デフォルトのセキュリティヘッダー

Spring Security は、安全なデフォルトを提供するためのセキュリティ HTTP レスポンスヘッダーのデフォルトセットを提供します。これらの各ヘッダーはベストプラクティスと見なされますが、すべてのクライアントがヘッダーを使用するわけではないため、追加のテストをお勧めします。

特定のヘッダーをカスタマイズできます。例: デフォルトが必要であるが、X-Frame-Options に SAMEORIGIN を指定したいとします。

これは、次の構成で実行できます。

デフォルトのセキュリティヘッダーのカスタマイズ
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.frameOptions(frameOptions -> frameOptions
					.sameOrigin()
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<frame-options policy="SAMEORIGIN" />
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                frameOptions {
                    sameOrigin = true
                }
            }
        }
        return http.build()
    }
}

デフォルトを追加せず、何を使用するかを明示的に制御したい場合は、デフォルトを無効にすることができます。次のコードリストは、その方法を示しています。

Spring Security の構成を使用する場合、以下はキャッシュ制御のみを追加します。

キャッシュコントロールヘッダーのカスタマイズ
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				// do not use any default headers unless explicitly listed
				.defaultsDisabled()
				.cacheControl(withDefaults())
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers defaults-disabled="true">
		<cache-control/>
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                // do not use any default headers unless explicitly listed
                defaultsDisabled = true
                cacheControl {
                }
            }
        }
        return http.build()
    }
}

必要に応じて、次の構成ですべての HTTP セキュリティレスポンスヘッダーを無効にできます。

すべての HTTP セキュリティヘッダーを無効にする
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers.disable());
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers disabled="true" />
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                disable()
            }
        }
        return http.build()
    }
}

キャッシュ制御

Spring Security には、デフォルトでキャッシュ制御ヘッダーが含まれています。

ただし、実際に特定のレスポンスをキャッシュする場合は、アプリケーションで HttpServletResponse.setHeader(String,String) [Oracle] (英語) を選択的に呼び出して、Spring Security によって設定されたヘッダーをオーバーライドできます。これを使用して、コンテンツ(CSS、JavaScript、イメージなど)が適切にキャッシュされるようにすることができます。

Spring Web MVC を使用する場合、これは通常、構成内で行われます。これを行う方法の詳細は、Spring リファレンスドキュメントの静的リソース部分にあります。

必要に応じて、Spring Security のキャッシュ制御 HTTP レスポンスヘッダーを無効にすることもできます。

キャッシュ制御が無効
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.cacheControl(cache -> cache.disable())
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<cache-control disabled="true"/>
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
       http {
            headers {
                cacheControl {
                    disable()
                }
            }
        }
        return http.build()
    }
}

コンテンツ型オプション

Spring Security には、デフォルトでコンテンツ型ヘッダーが含まれています。ただし、無効にすることができます。

コンテンツ型オプションが無効
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable())
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<content-type-options disabled="true"/>
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
       http {
            headers {
                contentTypeOptions {
                    disable()
                }
            }
        }
        return http.build()
    }
}

HTTP Strict Transport Security (HSTS)

デフォルトでは、Spring Security は Strict Transport Security ヘッダーを提供します。ただし、結果を明示的にカスタマイズできます。次の例では、HSTS を明示的に提供しています。

Strict Transport Security
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.httpStrictTransportSecurity(hsts -> hsts
					.includeSubDomains(true)
					.preload(true)
					.maxAgeInSeconds(31536000)
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<hsts
			include-subdomains="true"
			max-age-seconds="31536000"
			preload="true" />
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            headers {
                httpStrictTransportSecurity {
                    includeSubDomains = true
                    preload = true
                    maxAgeInSeconds = 31536000
                }
            }
        }
        return http.build()
    }
}

HTTP 公開鍵ピンニング (HPKP)

Spring Security は HTTP 公開鍵ピンニングのサーブレットサポートを提供しますが、推奨されなくなりました

HPKP ヘッダーは、次の構成で有効にできます。

HTTP 公開鍵ピンニング
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.httpPublicKeyPinning(hpkp -> hpkp
					.includeSubDomains(true)
					.reportUri("https://example.net/pkp-report")
					.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=")
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<hpkp
			include-subdomains="true"
			report-uri="https://example.net/pkp-report">
			<pins>
				<pin algorithm="sha256">d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=</pin>
				<pin algorithm="sha256">E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=</pin>
			</pins>
		</hpkp>
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            headers {
                httpPublicKeyPinning {
                    includeSubDomains = true
                    reportUri = "https://example.net/pkp-report"
                    pins = mapOf("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" to "sha256",
                            "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" to "sha256")
                }
            }
        }
        return http.build()
    }
}

X-Frame-Options

デフォルトでは、Spring Security は、X-Frame-Options を使用して、反射型 XSS 攻撃をブロックするようにブラウザーに指示します。

例: 次の構成では、Spring Security がブラウザーにコンテンツをブロックするように指示しないように指定しています。

X-Frame-Options: SAMEORIGIN
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.frameOptions(frameOptions -> frameOptions
					.sameOrigin()
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<frame-options
		policy="SAMEORIGIN" />
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            headers {
                frameOptions {
                    sameOrigin = true
                }
            }
        }
        return http.build()
    }
}

X-XSS-Protection

デフォルトでは、Spring Security はブラウザーに <<headers-xss-protection,X-XSS-Protection header> を使用して XSS Auditor を無効にするように指示します。ただし、このデフォルトは変更できます。例: 次の構成は、Spring Security が互換性のあるブラウザーにフィルタリングを有効にし、コンテンツをブロックするように指示することを指定します。

X-XSS-Protection のカスタマイズ
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.xssProtection(xss -> xss
					.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<xss-protection headerValue="1; mode=block"/>
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        // ...
        http {
            headers {
                xssProtection {
                    headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK
                }
            }
        }
        return http.build()
    }
}

コンテンツセキュリティポリシー (CSP)

Spring Security は、デフォルトではコンテンツセキュリティポリシーを追加しません。これは、アプリケーションのコンテキストを知らなければ、妥当なデフォルトを知ることができないためです。Web アプリケーションの作成者は、保護されたリソースを適用または監視するためのセキュリティポリシーを宣言する必要があります。

次のセキュリティポリシーを検討してください。

コンテンツセキュリティポリシーの例
Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/

前述のセキュリティポリシーを前提として、CSP ヘッダーを有効にできます。

コンテンツセキュリティポリシー
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.contentSecurityPolicy(csp -> csp
					.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<content-security-policy
			policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" />
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                contentSecurityPolicy {
                    policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
                }
            }
        }
        return http.build()
    }
}

CSP report-only ヘッダーを有効にするには、以下の構成を提供します。

コンテンツセキュリティポリシーレポートのみ
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.contentSecurityPolicy(csp -> csp
					.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
					.reportOnly()
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<content-security-policy
			policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
			report-only="true" />
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                contentSecurityPolicy {
                    policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
                    reportOnly = true
                }
            }
        }
        return http.build()
    }
}

リファラーポリシー

Spring Security は、デフォルトではリファラーポリシーヘッダーを追加しません。次の設定を使用して、リファラーポリシーヘッダーを有効にできます。

リファラーポリシー
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.referrerPolicy(referrer -> referrer
					.policy(ReferrerPolicy.SAME_ORIGIN)
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<referrer-policy policy="same-origin" />
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                referrerPolicy {
                    policy = ReferrerPolicy.SAME_ORIGIN
                }
            }
        }
        return http.build()
    }
}

機能ポリシー

Spring Security は、デフォルトでは機能ポリシーヘッダーを追加しません。次の Feature-Policy ヘッダーについて考えてみます。

機能ポリシーの例
Feature-Policy: geolocation 'self'

次の設定を使用して、前述の機能ポリシーヘッダーを有効にできます。

機能ポリシー
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.featurePolicy("geolocation 'self'")
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<feature-policy policy-directives="geolocation 'self'" />
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                featurePolicy("geolocation 'self'")
            }
        }
        return http.build()
    }
}

権限ポリシー

Spring Security は、デフォルトでは権限ポリシーヘッダーを追加しません。次の Permissions-Policy ヘッダーについて考えてみます。

権限 - ポリシーの例
Permissions-Policy: geolocation=(self)

次の構成を使用して、前述のアクセス許可ポリシーヘッダーを有効にできます。

権限 - ポリシー
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.permissionsPolicy(permissions -> permissions
					.policy("geolocation=(self)")
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<permissions-policy policy="geolocation=(self)" />
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                permissionPolicy {
                    policy = "geolocation=(self)"
                }
            }
        }
        return http.build()
    }
}

サイトデータのクリア

Spring Security は、デフォルトでは Clear-Site-Data ヘッダーを追加しません。次の Clear-Site-Data ヘッダーについて考えてみます。

Clear-Site-Data の例
Clear-Site-Data: "cache", "cookies"

次の構成で、ログアウト時に上記のヘッダーを送信できます。

Clear-Site-Data
  • Java

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.logout((logout) -> logout
                .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES)))
			);
		return http.build();
	}
}
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            logout {
                addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(CACHE, COOKIES)))
            }
        }
        return http.build()
    }
}

カスタムヘッダー

Spring Security には、より一般的なセキュリティヘッダーをアプリケーションに追加するのに便利なメカニズムがあります。ただし、カスタムヘッダーの追加を可能にするフックも提供します。

静的ヘッダー

すぐにサポートされていないカスタムセキュリティヘッダーをアプリケーションに挿入したい場合があります。次のカスタムセキュリティヘッダーを検討してください。

X-Custom-Security-Header: header-value

上記のヘッダーが与えられた場合、次の構成を使用して、レスポンスにヘッダーを追加できます。

StaticHeadersWriter
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"))
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<header name="X-Custom-Security-Header" value="header-value"/>
	</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                addHeaderWriter(StaticHeadersWriter("X-Custom-Security-Header","header-value"))
            }
        }
        return http.build()
    }
}

ヘッダーライター

名前空間または Java 構成が必要なヘッダーをサポートしていない場合、カスタム HeadersWriter インスタンスを作成するか、HeadersWriter のカスタム実装を提供することもできます。

次の例では、XFrameOptionsHeaderWriter のカスタムインスタンスを使用します。X-Frame-Options を明示的に構成する場合は、次の構成を使用して構成できます。

ヘッダーライター
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<header ref="frameOptionsWriter"/>
	</headers>
</http>
<!-- Requires the c-namespace.
See https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-c-namespace
-->
<beans:bean id="frameOptionsWriter"
	class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter"
	c:frameOptionsMode="SAMEORIGIN"/>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                addHeaderWriter(XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
            }
        }
        return http.build()
    }
}

DelegatingRequestMatcherHeaderWriter

場合によっては、特定のリクエストに対してのみヘッダーを記述したいことがあります。例: ログインページのみがフレーム化されないように保護したい場合があります。DelegatingRequestMatcherHeaderWriter を使用してこれを行うことができます。

次の構成例では、DelegatingRequestMatcherHeaderWriter を使用しています。

DelegatingRequestMatcherHeaderWriter Java 構成
  • Java

  • XML

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		RequestMatcher matcher = new AntPathRequestMatcher("/login");
		DelegatingRequestMatcherHeaderWriter headerWriter =
			new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
		http
			// ...
			.headers(headers -> headers
				.frameOptions(frameOptions -> frameOptions.disable())
				.addHeaderWriter(headerWriter)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<frame-options disabled="true"/>
		<header ref="headerWriter"/>
	</headers>
</http>

<beans:bean id="headerWriter"
	class="org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter">
	<beans:constructor-arg>
		<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"
			c:pattern="/login"/>
	</beans:constructor-arg>
	<beans:constructor-arg>
		<beans:bean
			class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter"/>
	</beans:constructor-arg>
</beans:bean>
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        val matcher: RequestMatcher = AntPathRequestMatcher("/login")
        val headerWriter = DelegatingRequestMatcherHeaderWriter(matcher, XFrameOptionsHeaderWriter())
       http {
            headers {
                frameOptions {
                    disable()
                }
                addHeaderWriter(headerWriter)
            }
        }
        return http.build()
    }
}