对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

如果您已经执行了 Reactive 应用程序的初始迁移步骤,那么您现在就可以执行特定于 Reactive 应用程序的步骤了。Spring中文文档

漏洞利用保护迁移

以下步骤与有关如何配置 CSRF 的更改相关。Spring中文文档

配置tokenFromMultipartDataEnabled

在 Spring Security 5.8 中,该方法已被弃用,取而代之的是 .tokenFromMultipartDataEnabledServerCsrfTokenRequestAttributeHandler#setTokenFromMultipartDataEnabledSpring中文文档

若要解决弃用问题,请执行以下代码:Spring中文文档

使用 DSL 进行配置tokenFromMultipartDataEnabled
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.csrf((csrf) -> csrf
			.tokenFromMultipartDataEnabled(true)
		);
	return http.build();
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	return http {
		// ...
		csrf {
			tokenFromMultipartDataEnabled = true
		}
	}
}

可以替换为:Spring中文文档

配置方式tokenFromMultipartDataEnabledServerCsrfTokenRequestAttributeHandler
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();
	requestHandler.setTokenFromMultipartDataEnabled(true);
	http
		// ...
		.csrf((csrf) -> csrf
			.csrfTokenRequestHandler(requestHandler)
		);
	return http.build();
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	val requestHandler = ServerCsrfTokenRequestAttributeHandler()
	requestHandler.tokenFromMultipartDataEnabled = true
	return http {
		// ...
		csrf {
			csrfTokenRequestHandler = requestHandler
		}
	}
}

防止 CSRF 违规

您可以使用以下配置选择加入 Spring Security 6 对 BREACH 保护的默认支持:CsrfTokenSpring中文文档

CsrfToken漏洞保护
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	XorServerCsrfTokenRequestAttributeHandler requestHandler = new XorServerCsrfTokenRequestAttributeHandler();
	// ...
	http
		// ...
		.csrf((csrf) -> csrf
			.csrfTokenRequestHandler(requestHandler)
		);
	return http.build();
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	val requestHandler = XorServerCsrfTokenRequestAttributeHandler()
	// ...
	return http {
		// ...
		csrf {
			csrfTokenRequestHandler = requestHandler
		}
	}
}

选择退出步骤

如果配置 CSRF BREACH 保护会给您带来麻烦,请查看以下方案以获得最佳选择退出行为:Spring中文文档

我正在使用 AngularJS 或其他 Javascript 框架

如果您使用 AngularJS 和 HttpClientXsrfModule(或其他框架中的类似模块)以及 ,您可能会发现自动支持不再起作用。CookieServerCsrfTokenRepository.withHttpOnlyFalse()Spring中文文档

在这种情况下,您可以配置Spring Security以验证cookie中的原始数据,同时使用具有委派的自定义自定义来保持CSRF BREACH 对响应的保护,如下所示:CsrfTokenServerCsrfTokenRequestHandlerSpring中文文档

配置 BREACH 保护以验证原始令牌CsrfToken
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	CookieServerCsrfTokenRepository tokenRepository = CookieServerCsrfTokenRepository.withHttpOnlyFalse();
	XorServerCsrfTokenRequestAttributeHandler delegate = new XorServerCsrfTokenRequestAttributeHandler();
	// Use only the handle() method of XorServerCsrfTokenRequestAttributeHandler and the
	// default implementation of resolveCsrfTokenValue() from ServerCsrfTokenRequestHandler
	ServerCsrfTokenRequestHandler requestHandler = delegate::handle;
	http
		// ...
		.csrf((csrf) -> csrf
			.csrfTokenRepository(tokenRepository)
			.csrfTokenRequestHandler(requestHandler)
		);

	return http.build();
}

@Bean
WebFilter csrfCookieWebFilter() {
	return (exchange, chain) -> {
		Mono<CsrfToken> csrfToken = exchange.getAttributeOrDefault(CsrfToken.class.getName(), Mono.empty());
		return csrfToken.doOnSuccess(token -> {
			/* Ensures the token is subscribed to. */
		}).then(chain.filter(exchange));
	};
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	val tokenRepository = CookieServerCsrfTokenRepository.withHttpOnlyFalse()
	val delegate = XorServerCsrfTokenRequestAttributeHandler()
	// Use only the handle() method of XorServerCsrfTokenRequestAttributeHandler and the
	// default implementation of resolveCsrfTokenValue() from ServerCsrfTokenRequestHandler
	val requestHandler = ServerCsrfTokenRequestHandler(delegate::handle)
	return http.invoke {
		// ...
		csrf {
			csrfTokenRepository = tokenRepository
			csrfTokenRequestHandler = requestHandler
		}
	}
}

@Bean
fun csrfCookieWebFilter(): WebFilter {
	return WebFilter { exchange, chain ->
		val csrfToken = exchange.getAttribute<Mono<CsrfToken>>(CsrfToken::class.java.name) ?: Mono.empty()
		csrfToken.doOnSuccess {
            /* Ensures the token is subscribed to. */
		}.then(chain.filter(exchange))
	}
}

出于其他原因,我需要选择退出 CSRF BREACH 保护

如果CSRF BREACH保护由于其他原因而无法为您工作,则可以使用以下配置选择退出:Spring中文文档

选择退出 BREACH 保护CsrfToken
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();
	http
		// ...
		.csrf((csrf) -> csrf
			.csrfTokenRequestHandler(requestHandler)
		);
	return http.build();
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	val requestHandler = ServerCsrfTokenRequestAttributeHandler()
	return http {
		// ...
		csrf {
			csrfTokenRequestHandler = requestHandler
		}
	}
}

用于方法安全性AuthorizationManager

如果您在进行这些更改时遇到问题,可以按照本节末尾的选择退出步骤进行操作。Spring中文文档

在 Spring Security 5.8 中,已添加到@EnableReactiveMethodSecurity,以允许应用程序选择加入 的功能。useAuthorizationManagerAuthorizationManagerSpring中文文档

更改为useAuthorizationManagertrue

要选择加入,请更改为如下所示:useAuthorizationManagertrueSpring中文文档

@EnableReactiveMethodSecurity
@EnableReactiveMethodSecurity

更改为:Spring中文文档

@EnableReactiveMethodSecurity(useAuthorizationManager = true)
@EnableReactiveMethodSecurity(useAuthorizationManager = true)

检查 sAnnotationConfigurationException

useAuthorizationManager激活对 Spring Security 不可重复或不兼容的注释的更严格执行。 如果在打开后在日志中看到 s,请按照异常消息中的说明清理应用程序的方法安全批注用法。useAuthorizationManagerAnnotationConfigurationExceptionSpring中文文档

选择退出步骤

如果您在响应式方法安全性方面遇到问题,可以通过更改以下内容来选择退出:AuthorizationManagerSpring中文文档

@EnableReactiveMethodSecurity
@EnableReactiveMethodSecurity
@EnableReactiveMethodSecurity(useAuthorizationManager = false)
@EnableReactiveMethodSecurity(useAuthorizationManager = false)

传播 sAuthenticationServiceException

AuthenticationFilterAuthenticationServiceException传播到 ServerAuthenticationEntryPoint。 由于 s 表示服务器端错误而不是客户端错误,因此在 6.0 中,此更改为将它们传播到容器。AuthenticationServiceExceptionSpring中文文档

配置为重新抛出ServerAuthenticationFailureHandlerAuthenticationServiceException

为 6.0 默认值做准备,并应配置为重新抛出 s。httpBasicoauth2ResourceServerAuthenticationServiceExceptionSpring中文文档

对于每个,为 和 构造适当的身份验证入口点:httpBasicoauth2ResourceServerSpring中文文档

ServerAuthenticationEntryPoint bearerEntryPoint = new BearerTokenServerAuthenticationEntryPoint();
ServerAuthenticationEntryPoint basicEntryPoint = new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED);
val bearerEntryPoint: ServerAuthenticationEntryPoint = BearerTokenServerAuthenticationEntryPoint()
val basicEntryPoint: ServerAuthenticationEntryPoint = HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)

如果对其中一种或两种机制使用自定义,请改用该自定义机制执行其余步骤。AuthenticationEntryPointSpring中文文档

然后,为每个构造和配置一个:ServerAuthenticationEntryPointFailureHandlerSpring中文文档

AuthenticationFailureHandler bearerFailureHandler = new ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint);
bearerFailureHandler.setRethrowAuthenticationServiceException(true);
AuthenticationFailureHandler basicFailureHandler = new ServerAuthenticationEntryPointFailureHandler(basicEntryPoint);
basicFailureHandler.setRethrowAuthenticationServiceException(true)
val bearerFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint)
bearerFailureHandler.setRethrowAuthenticationServiceException(true)
val basicFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(basicEntryPoint)
basicFailureHandler.setRethrowAuthenticationServiceException(true)

最后,将每个身份验证失败处理程序连接到 DSL,如下所示:Spring中文文档

http
    .httpBasic((basic) -> basic.authenticationFailureHandler(basicFailureHandler))
    .oauth2ResourceServer((oauth2) -> oauth2.authenticationFailureHandler(bearerFailureHandler))
http {
    httpBasic {
        authenticationFailureHandler = basicFailureHandler
    }
    oauth2ResourceServer {
        authenticationFailureHandler = bearerFailureHandler
    }
}

选择退出步骤

要选择退出 6.0 默认值并继续传递给 s,您可以按照与上述相同的步骤操作,但设置为 false。AuthenticationServiceExceptionServerAuthenticationEntryPointrethrowAuthenticationServiceExceptionSpring中文文档

如果对其中一种或两种机制使用自定义,请改用该自定义机制执行其余步骤。AuthenticationEntryPointSpring中文文档

添加批注@Configuration

在 6.0 中,从 和 中删除。@Configuration@EnableWebFluxSecurity@EnableReactiveMethodSecuritySpring中文文档

为此,无论您在哪里使用这些注释之一,您可能需要添加 . 例如,更改为:@Configuration@EnableReactiveMethodSecuritySpring中文文档

@EnableReactiveMethodSecurity
public class MyConfiguration {
	// ...
}
@EnableReactiveMethodSecurity
open class MyConfiguration {
	// ...
}
@Configuration
@EnableReactiveMethodSecurity
public class MyConfiguration {
	// ...
}
@Configuration
@EnableReactiveMethodSecurity
open class MyConfiguration {
	// ...
}

解决 OAuth2 客户端弃用问题

ServerOAuth2AuthorizedClientExchangeFilterFunction

该方法可以替换为以下方法之一:setAccessTokenExpiresSkew(…​)Spring中文文档

  • ClientCredentialsReactiveOAuth2AuthorizedClientProvider#setClockSkew(…​)Spring中文文档

  • RefreshTokenReactiveOAuth2AuthorizedClientProvider#setClockSkew(…​)Spring中文文档

  • JwtBearerReactiveOAuth2AuthorizedClientProvider#setClockSkew(…​)Spring中文文档

该方法可以替换为构造函数。setClientCredentialsTokenResponseClient(…​)ServerOAuth2AuthorizedClientExchangeFilterFunction(ReactiveOAuth2AuthorizedClientManager)Spring中文文档

有关详细信息,请参阅客户端凭据Spring中文文档

WebSessionOAuth2ServerAuthorizationRequestRepository

该方法没有直接替换。setAllowMultipleAuthorizationRequests(…​)Spring中文文档

UnAuthenticatedServerOAuth2AuthorizedClientRepository

该类没有直接替换。类的用法可以替换为 。UnAuthenticatedServerOAuth2AuthorizedClientRepositoryAuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerSpring中文文档

有关详细信息,请参阅客户端凭据Spring中文文档

添加到批注@Configuration@Enable*

在 6.0 中,Spring Security 的所有注解都被删除了。 虽然方便,但它与其他 Spring 项目不一致,尤其是 Spring Framework 的注解。 此外,在 Spring Framework 中引入对 的支持提供了另一个原因,可以从 Spring Security 的注解中删除元注解,并允许用户选择他们喜欢的配置模式。@Enable*@Configuration@Enable*@Configuration(proxyBeanMethods=false)@Configuration@Enable*Spring中文文档

删除了以下注释:@ConfigurationSpring中文文档

例如,如果您正在使用 ,则需要更改:@EnableWebFluxSecuritySpring中文文档

@EnableWebFluxSecurity
public class SecurityConfig {
	// ...
}
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
	// ...
}

这同样适用于上面列出的所有其他注释。Spring中文文档