# 安全 HTTP 响应标头

安全 HTTP 响应标头可以用来增加 Web 应用程序的安全性。本节专门讨论基于 WebFlux 的对安全 HTTP 响应头的支持。

# 默认安全标头

Spring 安全性提供了默认的安全 HTTP 响应标头集以提供安全的默认值。虽然这些标题中的每一个都被认为是最佳实践,但应该注意的是,并不是所有的客户机都使用这些标题,因此鼓励进行额外的测试。

你可以自定义特定的标题。例如,假设你希望使用默认值,但不希望为X-帧-选项指定SAMEORIGIN

你可以通过以下配置轻松地实现这一点:

例 1。自定义默认安全标头

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.frameOptions(frameOptions -> frameOptions
				.mode(Mode.SAMEORIGIN)
			)
		);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            frameOptions {
                mode = Mode.SAMEORIGIN
            }
        }
    }
}

如果不希望添加默认值,并且希望对应该使用的内容进行显式控制,则可以禁用默认值。下面举例说明:

例 2。禁用 HTTP 安全响应头

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers.disable());
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            disable()
        }
    }
}

# 缓存控制

Spring 默认情况下,安全性包括缓存控制标头。

然而,如果你实际上想要缓存特定的响应,你的应用程序可以有选择地将它们添加到ServerHtpResponse (opens new window)中,以覆盖由 Spring Security 设置的头。这对于确保 CSS、爪哇Script 和图像等内容被适当地缓存是有用的。

当使用 Spring WebFlux 时,这通常是在你的配置中完成的。关于如何做到这一点的详细信息可以在 Spring 参考文档的静态资源 (opens new window)部分中找到。

如果有必要,还可以禁用 Spring Security 的缓存控制 HTTP 响应头。

例 3。已禁用缓存控制

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.cache(cache -> cache.disable())
		);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            cache {
                disable()
            }
        }
    }
}

# 内容类型选项

Spring 默认情况下,安全性包括内容类型标头。但是,你可以通过以下方式禁用它:

例 4。禁用内容类型选项

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable())
		);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            contentTypeOptions {
                disable()
            }
        }
    }
}

#

Spring 默认情况下,Security 提供严格的运输安全报头。但是,你可以显式地定制结果。例如,下面是一个显式提供 HSTS 的示例:

例 5。严格的运输安全

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.hsts(hsts -> hsts
				.includeSubdomains(true)
				.preload(true)
				.maxAge(Duration.ofDays(365))
			)
		);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            hsts {
                includeSubdomains = true
                preload = true
                maxAge = Duration.ofDays(365)
            }
        }
    }
}

# X-帧-选项

默认情况下, Spring Security 使用X-帧-选项禁用在 iFrame 中的呈现。

你可以使用以下方法自定义框架选项以使用相同的原点:

例 6。x-frame-options:SameOrigin

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.frameOptions(frameOptions -> frameOptions
				.mode(SAMEORIGIN)
			)
		);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            frameOptions {
                mode = SAMEORIGIN
            }
        }
    }
}

# X-XSS-保护

默认情况下, Spring Security 指示浏览器使用 \<headers-xss-protection,X-XSS-Protection header>来阻止反射的 XSS 攻击。可以通过以下配置禁用X-XSS-Protection:

例 7。X-XSS-保护定制

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.xssProtection(xssProtection -> xssProtection.disable())
		);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            xssProtection {
                disable()
            }
        }
    }
}

#

Spring 安全默认情况下不添加内容安全策略,因为合理的默认情况是不可能在没有应用程序上下文的情况下知道的。Web 应用程序作者必须声明安全策略,以强制执行和/或监视受保护资源。

例如,给出以下安全策略:

例 8。内容安全策略示例

Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/

你可以启用 CSP 报头,如下所示:

例 9。内容安全策略

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.contentSecurityPolicy(policy -> policy
				.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
			)
		);
	return http.build();
}

Kotlin

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

要启用 CSPreport-only头,请提供以下配置:

例 10。仅提供内容安全策略报告

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.contentSecurityPolicy(policy -> policy
				.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
				.reportOnly()
			)
		);
	return http.build();
}

Kotlin

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

# 推荐人政策

Spring 默认情况下,安全性不添加推荐人政策标头。你可以使用如下所示的配置来启用 Referrer 策略标头:

例 11。Referrer 策略配置

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.referrerPolicy(referrer -> referrer
				.policy(ReferrerPolicy.SAME_ORIGIN)
			)
		);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            referrerPolicy {
                policy = ReferrerPolicy.SAME_ORIGIN
            }
        }
    }
}

# 特征策略

Spring 默认情况下,安全性不添加特征策略头。以下Feature-Policy标题:

例 12。功能策略示例

Feature-Policy: geolocation 'self'

你可以启用功能策略标头,如下所示:

例 13。功能策略配置

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.featurePolicy("geolocation 'self'")
		);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            featurePolicy("geolocation 'self'")
        }
    }
}

# 权限策略

Spring 默认情况下,安全性不添加权限策略标头。以下Permissions-Policy标题:

例 14。权限-策略示例

Permissions-Policy: geolocation=(self)

你可以启用权限策略标头,如下所示:

例 15。权限-策略配置

爪哇

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.headers(headers -> headers
			.permissionsPolicy(permissions -> permissions
				.policy("geolocation=(self)")
			)
		);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        // ...
        headers {
            permissionsPolicy {
                policy = "geolocation=(self)"
            }
        }
    }
}

# 清除站点数据

Spring 默认情况下,安全性不添加清除站点数据标头。以下 Clear-Site-Data 报头:

例 16。清除站点数据示例

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

可以通过以下配置在注销时发送:

例 17。清除站点数据配置

Java

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	ServerLogoutHandler securityContext = new SecurityContextServerLogoutHandler();
	ClearSiteDataServerHttpHeadersWriter writer = new ClearSiteDataServerHttpHeadersWriter(CACHE, COOKIES);
	ServerLogoutHandler clearSiteData = new HeaderWriterServerLogoutHandler(writer);
	DelegatingServerLogoutHandler logoutHandler = new DelegatingServerLogoutHandler(securityContext, clearSiteData);

	http
		// ...
		.logout()
			.logoutHandler(logoutHandler);
	return http.build();
}

Kotlin

@Bean
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    val securityContext: ServerLogoutHandler = SecurityContextServerLogoutHandler()
    val writer = ClearSiteDataServerHttpHeadersWriter(CACHE, COOKIES)
    val clearSiteData: ServerLogoutHandler = HeaderWriterServerLogoutHandler(writer)
    val customLogoutHandler = DelegatingServerLogoutHandler(securityContext, clearSiteData)

    return http {
        // ...
        logout {
            logoutHandler = customLogoutHandler
        }
    }
}