diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 5ccce227ed531a835f344f4e3efed5ff59ab5802..39045cddb21af9ccf2a31f2f4317df0d99e1b788 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -483,105 +483,159 @@ module.exports = { sidebarDepth: 2, collapsable: false, children: [ + "/spring-security/overview.md", + "/spring-security/prerequisites.md", "/spring-security/community.md", - "/spring-security/features-authentication-password-storage.md", + "/spring-security/whats-new.md", + "/spring-security/getting-spring-security.md", + "/spring-security/features.md", "/spring-security/features-authentication.md", + "/spring-security/features-authentication-password-storage.md", + "/spring-security/features-exploits.md", "/spring-security/features-exploits-csrf.md", "/spring-security/features-exploits-headers.md", "/spring-security/features-exploits-http.md", - "/spring-security/features-exploits.md", - "/spring-security/features-integrations-concurrency.md", + "/spring-security/features-integrations.md", "/spring-security/features-integrations-cryptography.md", "/spring-security/features-integrations-data.md", + "/spring-security/features-integrations-concurrency.md", "/spring-security/features-integrations-jackson.md", "/spring-security/features-integrations-localization.md", - "/spring-security/features-integrations.md", - "/spring-security/features.md", - "/spring-security/getting-spring-security.md", "/spring-security/modules.md", - "/spring-security/overview.md", - "/spring-security/prerequisites.md", - "/spring-security/reactive-authentication-logout.md", - "/spring-security/reactive-authentication-x509.md", - "/spring-security/reactive-authorization-authorize-http-requests.md", - "/spring-security/reactive-authorization-method.md", - "/spring-security/reactive-configuration-webflux.md", - "/spring-security/reactive-exploits-csrf.md", - "/spring-security/reactive-exploits-headers.md", - "/spring-security/reactive-exploits-http.md", - "/spring-security/reactive-exploits.md", - "/spring-security/reactive-getting-started.md", - "/spring-security/reactive-integrations-cors.md", - "/spring-security/reactive-integrations-rsocket.md", - "/spring-security/reactive-oauth2-client-authorization-grants.md", - "/spring-security/reactive-oauth2-client-authorized-clients.md", - "/spring-security/reactive-oauth2-client-client-authentication.md", - "/spring-security/reactive-oauth2-client-core.md", - "/spring-security/reactive-oauth2-client.md", - "/spring-security/reactive-oauth2-login-advanced.md", - "/spring-security/reactive-oauth2-login-core.md", - "/spring-security/reactive-oauth2-login.md", - "/spring-security/reactive-oauth2-resource-server-bearer-tokens.md", - "/spring-security/reactive-oauth2-resource-server-jwt.md", - "/spring-security/reactive-oauth2-resource-server-multitenancy.md", - "/spring-security/reactive-oauth2-resource-server-opaque-token.md", - "/spring-security/reactive-oauth2-resource-server.md", - "/spring-security/reactive-oauth2.md", - "/spring-security/reactive-test-method.md", - "/spring-security/reactive-test-web-authentication.md", - "/spring-security/reactive-test-web-csrf.md", - "/spring-security/reactive-test-web-oauth2.md", - "/spring-security/reactive-test-web-setup.md", - "/spring-security/reactive-test-web.md", - "/spring-security/reactive-test.md", - "/spring-security/reactive.md", "/spring-security/samples.md", - "/spring-security/servlet-appendix-database-schema.md", - "/spring-security/servlet-appendix-faq.md", - "/spring-security/servlet-appendix-namespace-authentication-manager.md", - "/spring-security/servlet-appendix-namespace-http.md", - "/spring-security/servlet-appendix-namespace-ldap.md", - "/spring-security/servlet-appendix-namespace-method-security.md", - "/spring-security/servlet-appendix-namespace-websocket.md", - "/spring-security/servlet-appendix-namespace.md", - "/spring-security/servlet-appendix.md", + "/spring-security/servlet.md", + "/spring-security/servlet-getting-started.md", "/spring-security/servlet-architecture.md", - "/spring-security/servlet-authentication-anonymous.md", + "/spring-security/servlet-authentication.md", "/spring-security/servlet-authentication-architecture.md", - "/spring-security/servlet-authentication-cas.md", - "/spring-security/servlet-authentication-events.md", - "/spring-security/servlet-authentication-jaas.md", - "/spring-security/servlet-authentication-logout.md", - "/spring-security/servlet-authentication-openid.md", + "/spring-security/servlet-authentication-passwords.md", + "/spring-security/servlet-authentication-passwords-input.md", + "/spring-security/servlet-authentication-passwords-form.md", "/spring-security/servlet-authentication-passwords-basic.md", "/spring-security/servlet-authentication-passwords-digest.md", - "/spring-security/servlet-authentication-passwords-form.md", - "/spring-security/servlet-authentication-passwords-input.md", - "/spring-security/servlet-authentication-passwords-storage-dao-authentication-provider.md", + "/spring-security/servlet-authentication-passwords-storage.md", "/spring-security/servlet-authentication-passwords-storage-in-memory.md", "/spring-security/servlet-authentication-passwords-storage-jdbc.md", - "/spring-security/servlet-authentication-passwords-storage-ldap.md", - "/spring-security/servlet-authentication-passwords-storage-password-encoder.md", - "/spring-security/servlet-authentication-passwords-storage-user-details-service.md", "/spring-security/servlet-authentication-passwords-storage-user-details.md", - "/spring-security/servlet-authentication-passwords-storage.md", - "/spring-security/servlet-authentication-passwords.md", - "/spring-security/servlet-authentication-preauth.md", - "/spring-security/servlet-authentication-rememberme.md", - "/spring-security/servlet-authentication-runas.md", + "/spring-security/servlet-authentication-passwords-storage-user-details-service.md", + "/spring-security/servlet-authentication-passwords-storage-password-encoder.md", + "/spring-security/servlet-authentication-passwords-storage-dao-authentication-provider.md", + "/spring-security/servlet-authentication-passwords-storage-ldap.md", "/spring-security/servlet-authentication-session-management.md", + "/spring-security/servlet-authentication-rememberme.md", + "/spring-security/servlet-authentication-openid.md", + "/spring-security/servlet-authentication-anonymous.md", + "/spring-security/servlet-authentication-preauth.md", + "/spring-security/servlet-authentication-jaas.md", + "/spring-security/servlet-authentication-cas.md", "/spring-security/servlet-authentication-x509.md", - "/spring-security/servlet-authentication.md", + "/spring-security/servlet-authentication-runas.md", + "/spring-security/servlet-authentication-logout.md", + "/spring-security/servlet-authentication-events.md", "/spring-security/servlet-authorization-.md", - "/spring-security/servlet-authorization-acls.md", "/spring-security/servlet-authorization-architecture.md", "/spring-security/servlet-authorization-authorize-http-requests.md", "/spring-security/servlet-authorization-authorize-requests.md", "/spring-security/servlet-authorization-expression-based.md", - "/spring-security/servlet-authorization-method-security.md", "/spring-security/servlet-authorization-secure-objects.md", + "/spring-security/servlet-authorization-method-security.md", + "/spring-security/servlet-authorization-acls.md", + "/spring-security/servlet-oauth2-.md", + "/spring-security/servlet-oauth2-login.md", + "/spring-security/servlet-oauth2-login-core.md", + "/spring-security/servlet-oauth2-login-advanced.md", + "/spring-security/servlet-oauth2-client.md", + "/spring-security/servlet-oauth2-client-core.md", + "/spring-security/servlet-oauth2-client-authorization-grants.md", + "/spring-security/servlet-oauth2-client-client-authentication.md", + "/spring-security/servlet-oauth2-client-authorized-clients.md", + "/spring-security/servlet-oauth2-resource-server.md", + "/spring-security/servlet-oauth2-resource-server-jwt.md", + "/spring-security/servlet-oauth2-resource-server-opaque-token.md", + "/spring-security/servlet-oauth2-resource-server-multitenancy.md", + "/spring-security/servlet-oauth2-resource-server-bearer-tokens.md", + "/spring-security/servlet-saml2.md", + "/spring-security/servlet-saml2-login.md", + "/spring-security/servlet-saml2-login-overview.md", + "/spring-security/servlet-saml2-login-authentication-requests.md", + "/spring-security/servlet-saml2-login-authentication.md", + "/spring-security/servlet-saml2-logout.md", + "/spring-security/servlet-saml2-metadata.md", + "/spring-security/servlet-exploits.md", + "/spring-security/servlet-exploits-csrf.md", + "/spring-security/servlet-exploits-headers.md", + "/spring-security/servlet-exploits-http.md", + "/spring-security/servlet-exploits-firewall.md", + "/spring-security/servlet-integrations.md", + "/spring-security/servlet-integrations-concurrency.md", + "/spring-security/servlet-integrations-jackson.md", + "/spring-security/servlet-integrations-localization.md", + "/spring-security/servlet-integrations-servlet-api.md", + "/spring-security/servlet-integrations-data.md", + "/spring-security/servlet-integrations-mvc.md", + "/spring-security/servlet-integrations-websocket.md", + "/spring-security/servlet-integrations-cors.md", + "/spring-security/servlet-integrations-jsp-taglibs.md", "/spring-security/servlet-configuration-java.md", - "/spring-security/servlet-configuration-kotlin.md" + "/spring-security/servlet-configuration-kotlin.md", + "/spring-security/servlet-configuration-xml-namespace.md", + "/spring-security/servlet-test.md", + "/spring-security/servlet-test-method.md", + "/spring-security/servlet-test-mockmvc.md", + "/spring-security/servlet-test-mockmvc-setup.md", + "/spring-security/servlet-test-mockmvc-request-post-processors.md", + "/spring-security/servlet-test-mockmvc-authentication.md", + "/spring-security/servlet-test-mockmvc-csrf.md", + "/spring-security/servlet-test-mockmvc-form-login.md", + "/spring-security/servlet-test-mockmvc-http-basic.md", + "/spring-security/servlet-test-mockmvc-oauth2.md", + "/spring-security/servlet-test-mockmvc-logout.md", + "/spring-security/servlet-test-mockmvc-request-builders.md", + "/spring-security/servlet-test-mockmvc-result-matchers.md", + "/spring-security/servlet-test-mockmvc-result-handlers.md", + "/spring-security/servlet-appendix.md", + "/spring-security/servlet-appendix-database-schema.md", + "/spring-security/servlet-appendix-namespace.md", + "/spring-security/servlet-appendix-namespace-authentication-manager.md", + "/spring-security/servlet-appendix-namespace-http.md", + "/spring-security/servlet-appendix-namespace-method-security.md", + "/spring-security/servlet-appendix-namespace-ldap.md", + "/spring-security/servlet-appendix-namespace-websocket.md", + "/spring-security/servlet-appendix-faq.md", + "/spring-security/reactive.md", + "/spring-security/reactive-getting-started.md", + "/spring-security/reactive-authentication-x509.md", + "/spring-security/reactive-authentication-logout.md", + "/spring-security/reactive-authorization-authorize-http-requests.md", + "/spring-security/reactive-authorization-method.md", + "/spring-security/reactive-oauth2.md", + "/spring-security/reactive-oauth2-login.md", + "/spring-security/reactive-oauth2-login-core.md", + "/spring-security/reactive-oauth2-login-advanced.md", + "/spring-security/reactive-oauth2-client.md", + "/spring-security/reactive-oauth2-client-core.md", + "/spring-security/reactive-oauth2-client-authorization-grants.md", + "/spring-security/reactive-oauth2-client-client-authentication.md", + "/spring-security/reactive-oauth2-client-authorized-clients.md", + "/spring-security/reactive-oauth2-resource-server.md", + "/spring-security/reactive-oauth2-resource-server-jwt.md", + "/spring-security/reactive-oauth2-resource-server-opaque-token.md", + "/spring-security/reactive-oauth2-resource-server-multitenancy.md", + "/spring-security/reactive-oauth2-resource-server-bearer-tokens.md", + "/spring-security/reactive-exploits.md", + "/spring-security/reactive-exploits-csrf.md", + "/spring-security/reactive-exploits-headers.md", + "/spring-security/reactive-exploits-http.md", + "/spring-security/reactive-integrations-cors.md", + "/spring-security/reactive-integrations-rsocket.md", + "/spring-security/reactive-test.md", + "/spring-security/reactive-test-method.md", + "/spring-security/reactive-test-web.md", + "/spring-security/reactive-test-web-setup.md", + "/spring-security/reactive-test-web-authentication.md", + "/spring-security/reactive-test-web-csrf.md", + "/spring-security/reactive-test-web-oauth2.md", + "/spring-security/reactive-configuration-webflux.md" ], initialOpenGroupIndex: 0 // 可选的, 默认值是 0 } diff --git a/docs/spring-security/reactive-oauth2-resource-server-opaque-token.md b/docs/spring-security/reactive-oauth2-resource-server-opaque-token.md index 0189d5e44462a57a2bed06e632cad55ff627eb16..0a3e69aa3a748f910a8061afc1ac901c4f7a9efb 100644 --- a/docs/spring-security/reactive-oauth2-resource-server-opaque-token.md +++ b/docs/spring-security/reactive-oauth2-resource-server-opaque-token.md @@ -74,7 +74,7 @@ Authorization: Bearer some-token-value # Resource Server will process this 这意味着当在配置中使用`@EnableWebFlux`时,它可以在`@Controller`方法中使用: -爪哇 +Java ``` @GetMapping("/foo") @@ -94,7 +94,7 @@ fun foo(authentication: BearerTokenAuthentication): Mono { 由于`BearerTokenAuthentication`持有`OAuth2AuthenticatedPrincipal`,这也意味着控制器方法也可以使用它: -爪哇 +Java ``` @GetMapping("/foo") @@ -118,7 +118,7 @@ fun foo(@AuthenticationPrincipal principal: OAuth2AuthenticatedPrincipal): Mono< 例如,如果使用`@EnableReactiveMethodSecurity`使你可以使用`@PreAuthorize`注释,则可以这样做: -爪哇 +Java ``` @PreAuthorize("principal?.attributes['sub'] = 'foo'") @@ -142,7 +142,7 @@ fun forFoosEyesOnly(): Mono { 第一个是将应用程序配置为资源服务器的`SecurityWebFilterChain`。当使用不透明令牌时,这个`SecurityWebFilterChain`看起来像: -爪哇 +Java ``` @Bean @@ -178,7 +178,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain 例 1。替换 SecurityWebFilterchain -爪哇 +Java ``` @EnableWebFluxSecurity @@ -225,7 +225,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain 例如,第二个`@Bean` Spring 启动创建了一个`ReactiveOpaqueTokenIntrospector`,它将`String`令牌解码为`OAuth2AuthenticatedPrincipal`的验证实例: -爪哇 +Java ``` @Bean @@ -247,11 +247,10 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { 并且它的配置可以使用`introspectionUri()`和`introspectionClientCredentials()`进行重写,或者使用`introspector()`进行替换。 -### ` - +### 使用`inrospectionUri()` 可以配置授权服务器的内省 URI[作为配置属性](#webflux-oauth2resourceserver-opaque-introspectionuri),也可以在 DSL 中提供它: -爪哇 +Java ``` @EnableWebFluxSecurity @@ -292,13 +291,11 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain } ``` -使用`introspectionUri()`优先于任何配置属性。 - -### ` +### 使用`introspectionUri()`优先于任何配置属性。 比`introspectionUri()`更强大的是`introspector()`,它将完全取代`ReactiveOpaqueTokenIntrospector`的任何引导自动配置: -爪哇 +Java ``` @EnableWebFluxSecurity @@ -343,7 +340,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain 或者,暴露`ReactiveOpaqueTokenIntrospector``@Bean`具有与`introspector()`相同的效果: -爪哇 +Java ``` @Bean @@ -371,7 +368,7 @@ OAuth2.0 内省端点通常会返回一个`scope`属性,指示它被授予的 这意味着,要保护具有由不透明令牌派生的作用域的端点或方法,相应的表达式应该包括以下前缀: -爪哇 +Java ``` @EnableWebFluxSecurity @@ -410,7 +407,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain 或类似于方法安全性: -爪哇 +Java ``` @PreAuthorize("hasAuthority('SCOPE_messages')") @@ -441,7 +438,7 @@ fun getMessages(): Flux { } 当然,这可以使用自定义`ReactiveOpaqueTokenIntrospector`进行定制,该自定义`ReactiveOpaqueTokenIntrospector`查看属性集并以其自己的方式进行转换: -爪哇 +Java ``` public class CustomAuthoritiesOpaqueTokenIntrospector implements ReactiveOpaqueTokenIntrospector { @@ -486,7 +483,7 @@ class CustomAuthoritiesOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector 在此之后,可以简单地将此自定义内省检测器配置为`@Bean`: -爪哇 +Java ``` @Bean @@ -529,7 +526,7 @@ spring: 在这种情况下,你可以创建一个自定义的`ReactiveOpaqueTokenIntrospector`,它仍然会到达端点,但随后会更新返回的主体,使其具有 JWTS 声明的属性: -爪哇 +Java ``` public class JwtOpaqueTokenIntrospector implements ReactiveOpaqueTokenIntrospector { @@ -581,7 +578,7 @@ class JwtOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector { 在此之后,可以简单地将此自定义内省检测器配置为`@Bean`: -爪哇 +Java ``` @Bean @@ -613,7 +610,7 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { * 调用并返回来自`/userinfo`端点的响应 -爪哇 +Java ``` public class UserInfoOpaqueTokenIntrospector implements ReactiveOpaqueTokenIntrospector { @@ -668,7 +665,7 @@ class UserInfoOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector { 如果你 AREN 不使用`spring-security-oauth2-client`,它仍然很简单。你只需要用你自己的`WebClient`实例调用`/userinfo`: -爪哇 +Java ``` public class UserInfoOpaqueTokenIntrospector implements ReactiveOpaqueTokenIntrospector { @@ -700,7 +697,7 @@ class UserInfoOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector { 无论哪种方式,在创建了`ReactiveOpaqueTokenIntrospector`之后,你应该将其发布为`@Bean`,以覆盖默认值: -爪哇 +Java ``` @Bean diff --git a/docs/spring-security/servlet-configuration-xml-namespace.md b/docs/spring-security/servlet-configuration-xml-namespace.md new file mode 100644 index 0000000000000000000000000000000000000000..1469d97c9f98edfa1f18984b152feb5c8f1deea4 --- /dev/null +++ b/docs/spring-security/servlet-configuration-xml-namespace.md @@ -0,0 +1,249 @@ +# 安全名称空间配置 + +## 导言 + +自 Spring 框架的2.0版本以来,名称空间配置一直可用。它允许你使用额外的XML模式中的元素来补充传统的 Spring bean应用程序上下文语法。你可以在 Spring [参考文献](https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/)中找到更多信息。名称空间元素可以简单地用于允许以更简洁的方式配置单个 Bean,或者更强大地,用于定义替代配置语法,该语法更紧密地匹配问题域,并向用户隐藏潜在的复杂性。一个简单的元素可能掩盖了一个事实,即多个bean和处理步骤正在被添加到应用程序上下文中。例如,将以下元素从安全名称空间添加到应用程序上下文中,将启动一个嵌入式LDAP服务器,以测试在应用程序中的使用情况: + +``` + +``` + +这比连接等效的 Apache 目录服务器bean要简单得多。最常见的替代配置需求由`ldap-server`元素上的属性支持,并且用户不必担心需要创建哪些bean以及 Bean 属性名称是什么。[1]。]在编辑应用程序上下文文件时使用一个好的XML编辑器,应该提供关于可用的属性和元素的信息。我们建议你尝试[Eclipse IDE with Spring Tools](https://spring.io/tools),因为它具有用于处理标准 Spring 名称空间的特殊功能。 + +要在应用程序上下文中开始使用安全名称空间,你需要在 Classpath 上使用`spring-security-config`jar。然后,你所需要做的就是将架构声明添加到应用程序上下文文件中: + +``` + + ... + +``` + +在你将看到的许多示例中(以及在示例应用程序中),我们通常使用“security”作为默认名称空间,而不是“bean”,这意味着我们可以省略所有安全名称空间元素上的前缀,从而使内容更易于阅读。如果你将你的应用程序上下文划分为不同的文件,并且将大多数安全配置都放在其中一个文件中,那么你可能也想这样做。然后,你的安全应用程序上下文文件将像这样启动 + +``` + + ... + +``` + +在本章中,我们将假设从现在开始使用这种语法。 + +### 命名空间的设计 + +名称空间旨在捕捉框架的最常见用途,并提供简化和简明的语法,以便在应用程序中启用它们。该设计基于框架内的大规模依赖关系,可以分为以下几个方面: + +* *Web/HTTP安全性*-最复杂的部分。设置用于应用框架身份验证机制的过滤器和相关服务bean,以保护URL,呈现登录和错误页面等等。 + +* *业务对象(方法)安全性*-用于保护服务层的选项。 + +* *身份验证管理器*-处理来自框架其他部分的身份验证请求。 + +* *AccessDecisionManager*-提供Web和方法安全性的访问决策。将注册一个默认的,但你也可以选择使用一个自定义的,使用正常的 Spring Bean 语法声明。 + +* *身份验证提供者*s-身份验证管理器对用户进行身份验证的机制。名称空间提供了对几个标准选项的支持,也是添加使用传统语法声明的自定义bean的一种方式。 + +* *UserDetailsService*-与身份验证提供程序密切相关,但通常也需要其他bean。 + +我们将在下面的小节中看到如何配置这些功能。 + +## 安全名称空间配置入门 + +在本节中,我们将研究如何构建名称空间配置,以使用框架的一些主要特性。让我们假设你最初希望尽快启动和运行,并通过一些测试登录向现有的Web应用程序添加身份验证支持和访问控制。然后,我们将研究如何转换为针对数据库或其他安全存储库进行身份验证。在后面的部分中,我们将介绍更高级的名称空间配置选项。 + +### web.xml配置 + +你需要做的第一件事是将以下过滤器声明添加到你的`web.xml`文件中: + +``` + +springSecurityFilterChain +org.springframework.web.filter.DelegatingFilterProxy + + + +springSecurityFilterChain +/* + +``` + +这提供了一个到 Spring 安全Web基础设施的钩子。`DelegatingFilterProxy`是一个 Spring 框架类,它委托给一个过滤器实现,该过滤器实现在你的应用程序上下文中被定义为 Spring Bean。在这种情况下, Bean 被命名为“SpringSecurityFilterChain”,这是由名称空间创建的内部基础设施 Bean,用于处理Web安全。请注意,你自己不应该使用这个名称。一旦你把这个添加到你的`web.xml`中,你就可以开始编辑你的应用程序上下文文件了。Web安全服务使用``元素进行配置。 + +### 最小\配置 + +要启用Web安全性,你所需要做的就是从一开始就启用它。 + +``` + + + + + +``` + +这表示我们希望我们的应用程序中的所有URL都是安全的,需要角色`ROLE_USER`来访问它们,我们希望使用带有用户名和密码的表单登录到应用程序,并且我们希望注册一个注销URL,这将允许我们从应用程序中注销。``元素是所有与Web相关的命名空间功能的父元素。``元素定义了一个`pattern`,它使用 Ant 路径样式语法[2],用于匹配实际执行方式的更多详细信息。]你还可以使用正则表达式匹配作为一种选择(有关更多详细信息,请参见名称空间附录)。`access`属性定义了匹配给定模式的请求的访问要求。对于默认配置,这通常是一个逗号分隔的角色列表,其中一个必须允许用户提出请求。前缀“role\_”是一个标记,表示应该与用户的权限进行简单的比较。换句话说,应该使用正常的基于角色的检查。 Spring 安全中的访问控制并不限于使用简单的角色(因此使用前缀来区分不同类型的安全属性)。稍后我们将看到解释如何改变[3]。在 Spring Security3.0中,还可以使用[EL表达式](../authorization/expression-based.html#el-access)填充属性。 + +| |你可以使用多个``元素来为不同的URL集定义不同的访问要求,但它们将按照列出的顺序进行计算,并使用第一个匹配项。,因此,你必须将最具体的匹配项放在顶部,
还可以添加一个`method`属性,以将匹配限制为特定的HTTP方法(`GET`,`POST`,`PUT`等)。| +|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +要添加一些用户,你可以直接在名称空间中定义一组测试数据: + +``` + + + + + + + + + +``` + +这是存储相同密码的安全方法的一个示例。密码的前缀是`{bcrypt}`,指示`DelegatingPasswordEncoder`,该命令支持任何配置的`PasswordEncoder`进行匹配,并使用bcrypt对密码进行哈希: + +``` + + + + + + + + + + +``` + +如果你熟悉该框架的预命名空间版本,你可能已经可以大致猜到这里发生了什么。``元素负责创建`FilterChainProxy`和它所使用的过滤器bean。常见的问题,如不正确的过滤器排序不再是一个问题,因为过滤器的位置是预先定义的。 + +``元素创建一个`DaoAuthenticationProvider` Bean,而``元素创建一个`InMemoryDaoImpl`。所有`authentication-provider`元素必须是``元素的子元素,该元素创建一个`ProviderManager`并向其注册身份验证提供者。你可以在[名称空间附录](../appendix/namespace/index.html#appendix-namespace)中找到有关创建的bean的更详细信息。如果你想开始了解框架中的重要类是什么以及它们是如何使用的,特别是如果你想在以后定制这些类,那么值得对此进行交叉检查。 + +上面的配置定义了两个用户、他们的密码和他们在应用程序中的角色(将用于访问控制)。还可以使用`user-service`上的`properties`属性从标准属性文件加载用户信息。有关文件格式的更多详细信息,请参见[内存中身份验证](../authentication/passwords/in-memory.html#servlet-authentication-inmemory)一节。使用``元素意味着用户信息将被身份验证管理器用于处理身份验证请求。你可以使用多个``元素来定义不同的认证源,并依次对每个元素进行查询。 + +此时,你应该能够启动你的应用程序,并且需要登录才能继续。尝试一下,或者尝试一下项目附带的“教程”示例应用程序。 + +#### 设置默认的登录后目标 + +如果试图访问受保护的资源时没有提示表单登录,那么`default-target-url`选项就会起作用。这是用户成功登录后将被带到的URL,默认为“/”。通过将`always-use-default-target`属性设置为“true”,你还可以配置一些东西,以便用户*总是*最终在此页面结束(无论登录是“按需”还是他们明确选择登录)。如果你的应用程序总是要求用户从“主页”页面开始,这是有用的,例如: + +``` + + + + + +``` + +为了获得对目的地的更多控制,你可以使用`authentication-success-handler-ref`属性作为`default-target-url`的替代选项。引用的 Bean 应该是`AuthenticationSuccessHandler`的实例。 + +## 高级Web功能 + +### 添加自己的过滤器 + +如果你以前使用过 Spring 安全性,那么你就会知道,该框架维护了一系列过滤器,以便应用其服务。你可能希望在特定位置将自己的筛选器添加到堆栈中,或者使用 Spring 安全筛选器,该筛选器目前没有名称空间配置选项(例如,CAS)。或者,你可能希望使用标准名称空间过滤器的定制版本,例如`UsernamePasswordAuthenticationFilter`,它是由``元素创建的,利用了一些额外的配置选项,这些额外的配置选项可以通过显式地使用 Bean 来获得。既然过滤器链不是直接公开的,那么如何使用名称空间配置来实现这一点呢? + +在使用名称空间时,总是严格执行过滤器的顺序。在创建应用程序上下文时,过滤器bean按名称空间处理代码进行排序,标准 Spring 安全过滤器在名称空间和众所周知的位置中都有一个别名。 + +| |在以前的版本中,排序是在应用程序上下文的后处理过程中,在过滤器实例被创建之后进行的,
在版本3.0中,排序现在是在 Bean 元数据级别完成的,在类被实例化之前。
这对于如何将自己的筛选器添加到堆栈有影响,因为在解析``元素期间,必须知道整个筛选器列表,所以语法在3.0中略有变化。| +|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +创建过滤器的过滤器、别名和名称空间元素/属性在[标准过滤器别名和排序](#filter-stack)中显示。过滤器是按照它们在过滤器链中出现的顺序列出的。 + +| Alias | Filter Class |名称空间元素或属性| +|------------------------------|-----------------------------------------------------|-------------------------------------------------------| +| CHANNEL\_FILTER | `ChannelProcessingFilter` |`http/[[email protected]](/cdn-cgi/l/email-protection)`| +| SECURITY\_CONTEXT\_FILTER | `SecurityContextPersistenceFilter` |`http`| +| CONCURRENT\_SESSION\_FILTER | `ConcurrentSessionFilter` |`session-management/concurrency-control`| +| HEADERS\_FILTER | `HeaderWriterFilter` |`http/headers`| +| CSRF\_FILTER | `CsrfFilter` |`http/csrf`| +| LOGOUT\_FILTER | `LogoutFilter` |`http/logout`| +| X509\_FILTER | `X509AuthenticationFilter` |`http/x509`| +| PRE\_AUTH\_FILTER |`AbstractPreAuthenticatedProcessingFilter` Subclasses|不适用| +| CAS\_FILTER | `CasAuthenticationFilter` |不适用| +| FORM\_LOGIN\_FILTER | `UsernamePasswordAuthenticationFilter` |`http/form-login`| +| BASIC\_AUTH\_FILTER | `BasicAuthenticationFilter` |`http/http-basic`| +|SERVLET\_API\_SUPPORT\_FILTER | `SecurityContextHolderAwareRequestFilter` |`http/@servlet-api-provision`| +| JAAS\_API\_SUPPORT\_FILTER | `JaasApiIntegrationFilter` |`http/@jaas-api-provision`| +| REMEMBER\_ME\_FILTER | `RememberMeAuthenticationFilter` |`http/remember-me`| +| ANONYMOUS\_FILTER | `AnonymousAuthenticationFilter` |`http/anonymous`| +| SESSION\_MANAGEMENT\_FILTER | `SessionManagementFilter` |`session-management`| +|EXCEPTION\_TRANSLATION\_FILTER| `ExceptionTranslationFilter` |`http`| +|FILTER\_SECURITY\_INTERCEPTOR | `FilterSecurityInterceptor` |`http`| +| SWITCH\_USER\_FILTER | `SwitchUserFilter` |不适用| + +你可以将自己的筛选器添加到堆栈中,使用`custom-filter`元素和其中一个名称来指定筛选器应该出现在以下位置: + +``` + + + + + +``` + +如果希望在堆栈中的另一个过滤器之前或之后插入过滤器,还可以使用`after`或`before`属性。名称“first”和“last”可以与`position`属性一起使用,以表明你希望你的筛选器分别出现在整个堆栈之前或之后。 + +| |避免过滤器位置冲突

如果你要插入一个自定义过滤器,该过滤器的位置可能与名称空间创建的标准过滤器的位置相同,那么这一点很重要你没有错误地包含名称空间版本。,
删除任何创建过滤器的元素,这些过滤器的功能是你想要替换的,

注意,你不能替换使用``元素本身创建的过滤器-`SecurityContextPersistenceFilter`,`ExceptionTranslationFilter`或`FilterSecurityInterceptor`。
默认情况下添加了其他一些过滤器,但你可以禁用它们。
默认情况下添加了一个`AnonymousAuthenticationFilter`,除非你禁用了[session-fixation protection](../authentication/session-management.html#ns-session-fixation),否则还将向过滤器链中添加一个`SessionManagementFilter`。| +|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +如果要替换需要身份验证入口点的名称空间过滤器(即未经身份验证的用户试图访问安全资源而触发身份验证过程),还需要添加自定义入口点 Bean。 + +## 方法安全性 + +Spring 从版本2.0开始,安全性在很大程度上改进了对向服务层方法添加安全性的支持。它提供了对JSR-250注释安全性的支持,以及框架的原始`@Secured`注释。从3.0开始,你还可以使用New[基于表达式的注释](../authorization/expression-based.html#el-access)。你可以对单个 Bean 应用安全性,使用`intercept-methods`元素来装饰 Bean 声明,或者可以使用AspectJ样式的切入点在整个服务层中保护多个bean。 + +## 默认的accessesdecisionManager + +本节假定你对 Spring Security中的访问控制的底层体系结构有一定的了解。如果你不这样做,你可以跳过它,稍后再来讨论它,因为这一部分只与那些需要进行一些定制以使用比简单的基于角色的安全性更多功能的人相关。 + +当你使用名称空间配置时,将自动为你注册一个`AccessDecisionManager`的默认实例,该实例将用于为方法调用和Web URL访问做出访问决策,基于你在`intercept-url`和`protect-pointcut`声明中指定的访问属性(如果你使用的是注释安全方法,则在注释中指定)。 + +默认的策略是使用`AffirmativeBased``AccessDecisionManager`和`RoleVoter`。你可以在[授权](../authorization/architecture.html#authz-arch)一章中找到更多有关这些的信息。 + +### 自定义accessDecisionManager + +如果需要使用更复杂的访问控制策略,那么很容易为方法和Web安全性设置替代方案。 + +对于方法安全性,你可以通过将`global-method-security`上的`access-decision-manager-ref`属性设置为应用程序上下文中适当的`id` Bean 中的`id`来实现此目的: + +``` + +... + +``` + +Web安全性的语法是相同的,但是在`http`元素上: + +``` + +... + +``` + +--- + +[1](#_footnoteref_1)。你可以在关于Xref的章节中找到有关`ldap-server`元素使用情况的更多信息: Servlet/authentication/unpwd/ldap.ADOC# Servlet-authentication-ldap[ldap身份验证] + +[2](#_footnoteref_2)。参见Xref部分: Servlet/exploits/firewall.ADOC# Servlet-HttpFirewall[`HttpFirewall` + +[3](#_footnoteref_3)。对`access`属性中逗号分隔的值的解释取决于所使用的[AccessDecisionManager](#ns-access-manager)的实现。 + +[Kotlin Configuration](kotlin.html)[Testing](../test/index.html) + diff --git a/docs/spring-security/servlet-exploits-csrf.md b/docs/spring-security/servlet-exploits-csrf.md new file mode 100644 index 0000000000000000000000000000000000000000..92ce7c70e3a351c4711d8fdb750366feaa12d834 --- /dev/null +++ b/docs/spring-security/servlet-exploits-csrf.md @@ -0,0 +1,389 @@ +# Servlet 环境中的跨站点请求伪造 + +本节讨论 Spring Security对 Servlet 环境的[跨站点请求伪造](../../features/exploits/csrf.html#csrf)支持。 + +## 使用 Spring 安全CSRF保护 + +使用 Spring Security的CSRF保护的步骤概述如下: + +* [使用适当的HTTP动词](#servlet-csrf-idempotent) + +* [配置CSRF保护](#servlet-csrf-configure) + +* [包括CSRF令牌](#servlet-csrf-include) + +### 使用适当的HTTP动词 + +防止CSRF攻击的第一步是确保你的网站使用正确的HTTP动词。这在[安全的方法必须是幂等的。](../../features/exploits/csrf.html#csrf-protection-idempotent)中有详细介绍。 + +### 配置CSRF保护 + +下一步是在应用程序中配置 Spring Security的CSRF保护。 Spring 默认情况下,Security的CSRF保护是启用的,但你可能需要定制配置。下面是一些常见的定制。 + +#### 自定义CSRFTokenRepository + +Spring 默认情况下,Security使用`HttpSessionCsrfTokenRepository`将预期的CSRF令牌存储在`HttpSession`中。在某些情况下,用户可能希望配置自定义`CsrfTokenRepository`。例如,可能希望将cookie中的`CsrfToken`持久化到[支持基于JavaScript的应用程序](#servlet-csrf-include-ajax-auto)。 + +默认情况下,`CookieCsrfTokenRepository`将写到一个名为`XSRF-TOKEN`的cookie,并从一个名为`X-XSRF-TOKEN`的头部或HTTP参数`_csrf`读取它。这些默认值来自[AngularJS](https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection) + +可以使用以下方法在XML中配置`CookieCsrfTokenRepository`: + +例1.使用XML配置在cookie中存储CSRF令牌 + +``` + + + + + +``` + +| |示例显式设置`cookieHttpOnly=false`.
这是允许JavaScript(即Angularjs)读取它所必需的。
如果不需要直接使用JavaScript读取cookie的能力,建议省略`cookieHttpOnly=false`以提高安全性。| +|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +你可以在 Java 配置中使用以下方法配置`CookieCsrfTokenRepository`: + +例2.在cookie中存储CSRF令牌 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends + WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) { + http + .csrf(csrf -> csrf + .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) + ); + } +} +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + csrf { + csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse() + } + } + } +} +``` + +| |示例显式设置`cookieHttpOnly=false`.
这是允许JavaScript(即Angularjs)读取它所必需的。
如果不需要直接使用JavaScript读取cookie的能力,建议省略`cookieHttpOnly=false`(通过使用`new CookieCsrfTokenRepository()`代替)以提高安全性。| +|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +#### 禁用CSRF保护 + +默认情况下启用了CSRF保护。但是,如果CSRF保护[对你的应用程序来说是有意义的](../../features/exploits/csrf.html#csrf-when),则禁用CSRF保护非常简单。 + +下面的XML配置将禁用CSRF保护。 + +例3.禁用CSRF XML配置 + +``` + + + + +``` + +下面的 Java 配置将禁用CSRF保护。 + +例4.禁用CSRF + +Java + +``` +@Configuration +@EnableWebSecurity +public class WebSecurityConfig extends + WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) { + http + .csrf(csrf -> csrf.disable()); + } +} +``` + +Kotlin + +``` +@Configuration +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + csrf { + disable() + } + } + } +} +``` + +### 包括CSRF令牌 + +为了使[同步器令牌模式](../../features/exploits/csrf.html#csrf-protection-stp)能够抵御CSRF攻击,我们必须在HTTP请求中包含实际的CSRF令牌。这必须包含在请求的一部分(即表单参数、HTTP头等)中,而该部分不是由浏览器自动包含在HTTP请求中的。 + +Spring Security的[CsrfFilter](https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfFilter.html)将[CsrfToken](https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html)公开为名为`HttpServletRequest`的属性。这意味着,任何视图技术都可以访问`CsrfToken`以将预期的令牌公开为[form](#servlet-csrf-include-form-attr)或[meta tag](#servlet-csrf-include-ajax-meta-attr)。幸运的是,下面列出的集成使得在[form](#servlet-csrf-include-form)和[ajax](#servlet-csrf-include-ajax)请求中包含令牌变得更加容易。 + +#### 表单URL编码 + +为了发布HTML表单,CSRF令牌必须作为隐藏输入包含在表单中。例如,呈现的HTML可能看起来像: + +例5. CSRF令牌HTML + +``` + +``` + +接下来,我们将讨论将CSRF令牌以一种形式包含为隐藏输入的各种方法。 + +##### CSRF令牌自动包含 + +Spring Security的CSRF支持通过其[CsrfrequestDataValueProcessor](https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/servlet/support/csrf/CsrfRequestDataValueProcessor.html)提供与 Spring 的[RequestDataValueProcessor](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/support/RequestDataValueProcessor.html)的集成。这意味着,如果你利用[Spring’s form tag library](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib)、[Thymeleaf](https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor)或与`RequestDataValueProcessor`集成的任何其他视图技术,那么具有不安全的HTTP方法(即POST)的窗体将自动包括实际的CSRF令牌。 + +##### csrfinput标记 + +如果你正在使用JSP,那么你可以使用[Spring’s form tag library](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib)。但是,如果这不是一个选项,你也可以很容易地将令牌包含在[csrfInput](../integrations/jsp-taglibs.html#taglibs-csrfinput)标记中。 + +##### CSRFToken请求属性 + +如果用于在请求中包含实际CSRF令牌的[其他选择](#servlet-csrf-include)不起作用,则可以利用以下事实:`CsrfToken`[is exposed](#servlet-csrf-include)作为`HttpServletRequest`属性,该属性名为`_csrf`。 + +使用JSP执行此操作的示例如下所示: + +例6.具有请求属性的表单中的CSRF令牌 + +``` + +
+ + +
+``` + +#### Ajax和JSON请求 + +如果你正在使用JSON,那么就不可能在HTTP参数中提交CSRF令牌。相反,你可以在HTTP头中提交令牌。 + +在下面的部分中,我们将讨论在基于JavaScript的应用程序中将CSRF令牌作为HTTP请求头包含在内的各种方法。 + +##### 自动包含 + +Spring 安全性可以很容易地[configured](#servlet-csrf-configure-custom-repository)将预期的CSRF令牌存储在cookie中。通过将预期的CSRF存储在Cookie中,像[AngularJS](https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection)这样的JavaScript框架将自动在HTTP请求头中包含实际的CSRF令牌。 + +##### 元标签 + +[在cookie中暴露CSRF](#servlet-csrf-include-form-auto)的另一种模式是在`meta`标记中包含CSRF标记。HTML可能看起来是这样的: + +例7. CSRF元标记HTML + +``` + + + + + + + +``` + +一旦元标记包含CSRF令牌,JavaScript代码将读取元标记并将CSRF令牌作为报头。如果你正在使用jQuery,可以通过以下方式完成此操作: + +例8. Ajax发送CSRF令牌 + +``` +$(function () { + var token = $("meta[name='_csrf']").attr("content"); + var header = $("meta[name='_csrf_header']").attr("content"); + $(document).ajaxSend(function(e, xhr, options) { + xhr.setRequestHeader(header, token); + }); +}); +``` + +###### CSRFMeta标签 + +如果你正在使用JSP,那么将CSRF令牌写入`meta`标记的一种简单方法是利用[csrfMeta](../integrations/jsp-taglibs.html#taglibs-csrfmeta)标记。 + +###### CSRFToken请求属性 + +如果用于在请求中包含实际CSRF令牌的[其他选择](#servlet-csrf-include)不起作用,则可以利用以下事实:`CsrfToken`[is exposed](#servlet-csrf-include)作为`HttpServletRequest`属性,该属性名为`_csrf`。使用JSP执行此操作的示例如下所示: + +例9. CSRF元标记JSP + +``` + + + + + + + + +``` + +## CSRF考虑因素 + +在实施针对CSRF攻击的保护时,有几个特殊的考虑因素需要考虑。本节讨论与 Servlet 环境相关的那些考虑因素。有关更一般性的讨论,请参见[CSRF考虑因素](../../features/exploits/csrf.html#csrf-considerations)。 + +### 登录 + +这是重要的[需要CSRF才能登录](../../features/exploits/csrf.html#csrf-considerations-login)请求,以防止伪造日志的企图。 Spring Security的 Servlet 支持是开箱即用的。 + +### 注销 + +重要的是[需要CSRF才能注销](../../features/exploits/csrf.html#csrf-considerations-logout)请求,以防止伪造注销尝试。如果启用了CSRF保护(默认), Spring Security的`LogoutFilter`将仅处理HTTP POST。这确保了注销需要CSRF令牌,并且恶意用户不能强制注销你的用户。 + +最简单的方法是使用表单注销。如果你真的想要一个链接,可以使用JavaScript让该链接执行一个POST(例如,可能在一个隐藏的表单上)。对于禁用了JavaScript的浏览器,你可以选择让链接将用户带到将执行POST的注销确认页面。 + +如果你真的想使用HTTP GET与注销,你可以这样做,但请记住,这通常是不推荐的。例如,以下 Java 配置将使用任何HTTP方法请求的URL执行注销: + +例10.用HTTP GET登出 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends + WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) { + http + .logout(logout -> logout + .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) + ); + } +} +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + logout { + logoutRequestMatcher = AntPathRequestMatcher("/logout") + } + } + } +} +``` + +### CSRF和会话暂停 + +默认情况下, Spring Security将CSRF令牌存储在`HttpSession`中。这可能导致会话过期的情况,这意味着没有预期的CSRF令牌来验证。 + +我们已经讨论了[一般解决方案](../../features/exploits/csrf.html#csrf-considerations-login)到会话的超时。本节讨论CSRF超时的细节,因为它与 Servlet 支持有关。 + +将预期的CSRF令牌的存储更改为cookie中的存储是很简单的。有关详细信息,请参阅[自定义CSRFTokenRepository](#servlet-csrf-configure-custom-repository)部分。 + +如果一个令牌确实过期了,你可能希望通过指定一个自定义`AccessDeniedHandler`来定制它的处理方式。自定义`AccessDeniedHandler`可以以任何方式处理`InvalidCsrfTokenException`。对于如何自定义`AccessDeniedHandler`的示例,请参阅为[xml](../appendix/namespace/http.html#nsa-access-denied-handler)和[Java configuration](https://github.com/spring-projects/spring-security/tree/5.6.2/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java#L64)提供的链接。 + +### + +我们有[已经讨论过了](../../features/exploits/csrf.html#csrf-considerations-multipart)如何保护多部分请求(文件上传)不受CSRF攻击导致[鸡和蛋](https://en.wikipedia.org/wiki/Chicken_or_the_egg)问题。本节讨论如何在 Servlet 应用程序中实现将CSRF令牌放置在[body](#servlet-csrf-considerations-multipart-body)和[url](#servlet-csrf-considerations-multipart-url)中。 + +| |关于使用具有 Spring 的多部分表单的更多信息,可以在 Spring 引用的[1.1.11. 多部分旋转变压器](https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart)部分和[MultipartFilter Javadoc](https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html)中找到。| +|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +#### 将CSRF标记放入体内 + +我们有[已经讨论过了](../../features/exploits/csrf.html#csrf-considerations-multipart-body)在主体中放置CSRF标记的权衡。在本节中,我们将讨论如何配置 Spring 安全性,以便从主体读取CSRF。 + +为了从主体中读取CSRF令牌,在 Spring 安全过滤器之前指定了`MultipartFilter`。在 Spring 安全过滤器之前指定`MultipartFilter`意味着没有调用`MultipartFilter`的授权,这意味着任何人都可以在你的服务器上放置临时文件。但是,只有经过授权的用户才能提交由你的应用程序处理的文件。通常,这是推荐的方法,因为临时文件上传对大多数服务器的影响可以忽略不计。 + +为了确保`MultipartFilter`是在 Spring 安全过滤器 Java 配置之前指定的,用户可以在SpringSecurityFilterchain之前覆盖,如下所示: + +例11.初始化器MultipartFilter + +Java + +``` +public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer { + + @Override + protected void beforeSpringSecurityFilterChain(ServletContext servletContext) { + insertFilters(servletContext, new MultipartFilter()); + } +} +``` + +Kotlin + +``` +class SecurityApplicationInitializer : AbstractSecurityWebApplicationInitializer() { + override fun beforeSpringSecurityFilterChain(servletContext: ServletContext?) { + insertFilters(servletContext, MultipartFilter()) + } +} +``` + +为了确保在使用XML配置的 Spring 安全过滤器之前指定`MultipartFilter`,用户可以确保将`MultipartFilter`元素的\元素放置在web.xml中的SpringSecurityFilterchain之前,如下所示: + +示例12.web.xml-multipartfilter + +``` + + MultipartFilter + org.springframework.web.multipart.support.MultipartFilter + + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy + + + MultipartFilter + /* + + + springSecurityFilterChain + /* + +``` + +#### 在URL中包含CSRF令牌 + +如果允许未经授权的用户上传临时文件是不可接受的,则另一种选择是将`MultipartFilter`置于 Spring 安全过滤器之后,并将CSRF作为查询参数包含在表单的动作属性中。由于`CsrfToken`被公开为`HttpServletRequest`[请求属性](#servlet-csrf-include),因此我们可以使用它来创建带有CSRF令牌的`action`。下面显示了一个带有JSP的示例。 + +例13. CSRF令牌正在运行 + +``` +
+``` + +### HiddenHttpMethodFilter + +我们有[已经讨论过了](../../features/exploits/csrf.html#csrf-considerations-multipart-body)在主体中放置CSRF标记的权衡。 + +在 Spring 的 Servlet 支持中,覆盖HTTP方法是使用[HiddenHttpMethodFilter](https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html)完成的。更多信息可以在参考文档的[HTTP方法转换](https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-rest-method-conversion)部分中找到。 + +[保护免受剥削](index.html)[安全HTTP响应标头](headers.html) + diff --git a/docs/spring-security/servlet-exploits-firewall.md b/docs/spring-security/servlet-exploits-firewall.md new file mode 100644 index 0000000000000000000000000000000000000000..14a9dd255fec48a1599cec1d4939f86e1158267c --- /dev/null +++ b/docs/spring-security/servlet-exploits-firewall.md @@ -0,0 +1,202 @@ +# HttpFirewall + +在针对你定义的模式进行测试时,了解该机制是什么以及使用了什么URL值是很重要的。 + +Servlet 规范为`HttpServletRequest`定义了几个属性,这些属性可以通过getter方法访问,并且我们可能希望对其进行匹配。它们是`contextPath`,`servletPath`,`pathInfo`和`queryString`。 Spring 安全性只对保护应用程序内的路径感兴趣,因此`contextPath`被忽略。不幸的是, Servlet 规范并没有确切地定义`servletPath`和`pathInfo`对于特定的请求URI的值将包含什么。例如,一个URL的每个路径段可以包含参数,如[RFC 2396](https://www.ietf.org/rfc/rfc2396.txt)[1]。规范没有明确说明是否应该将这些值包含在`servletPath`和`pathInfo`值中,并且不同的容器之间的行为是不同的。当应用程序部署在不从这些值中删除路径参数的容器中时,存在这样的危险:攻击者可能会将它们添加到所请求的URL中,从而导致模式匹配意外成功或失败。[2]。传入URL中的其他变体也是可能的。例如,它可能包含路径遍历序列(如`/../`)或多个前向斜杠(`//`),这也可能导致模式匹配失败。一些容器在执行 Servlet 映射之前将这些规范化,但其他容器则不这样做。为了防止此类问题,`FilterChainProxy`使用`HttpFirewall`策略来检查和包装请求。默认情况下,未规范化的请求会被自动拒绝,并且为了匹配的目的,会删除路径参数和重复的斜杠。[3]。因此,使用`FilterChainProxy`来管理安全筛选链是非常重要的。请注意,`servletPath`和`pathInfo`值是由容器解码的,因此你的应用程序不应该有任何包含半冒号的有效路径,因为为了匹配的目的,这些部分将被删除。 + +如上所述,默认策略是使用 Ant 样式的路径进行匹配,这可能是大多数用户的最佳选择。该策略在类`AntPathRequestMatcher`中实现,该类使用 Spring 的`AntPathMatcher`对串联的`servletPath`和`pathInfo`执行不区分大小写的模式匹配,忽略`queryString`。 + +如果出于某种原因,你需要一个更强大的匹配策略,那么可以使用正则表达式。那么策略执行`RegexRequestMatcher`。有关此类的更多信息,请参见Javadoc。 + +在实践中,我们建议你在服务层使用方法安全性来控制对应用程序的访问,而不是完全依赖于在Web-Application级别定义的安全约束的使用。URL会发生变化,很难考虑到应用程序可能支持的所有可能的URL,以及如何操纵请求。你应该试着把自己限制在几条简单易懂的路径上。始终尝试使用“默认拒绝”方法,其中你有一个包罗万象的通配符(/**或**)在最后定义并拒绝访问。 + +在服务层定义的安全性要强大得多,也更难绕过,因此你应该始终利用 Spring Security的方法安全性选项。 + +`HttpFirewall`还通过拒绝HTTP响应头中的新行字符来防止[HTTP响应拆分](https://www.owasp.org/index.php/HTTP_Response_Splitting)。 + +默认情况下使用`StrictHttpFirewall`。此实现拒绝似乎是恶意的请求。如果对你的需求来说过于严格,那么你可以自定义拒绝的请求类型。然而,重要的是,你要知道这可能会使你的应用程序受到攻击。例如,如果你希望利用 Spring MVC的矩阵变量,可以使用以下配置: + +例1.允许矩阵变量 + +Java + +``` +@Bean +public StrictHttpFirewall httpFirewall() { + StrictHttpFirewall firewall = new StrictHttpFirewall(); + firewall.setAllowSemicolon(true); + return firewall; +} +``` + +XML + +``` + + + +``` + +Kotlin + +``` +@Bean +fun httpFirewall(): StrictHttpFirewall { + val firewall = StrictHttpFirewall() + firewall.setAllowSemicolon(true) + return firewall +} +``` + +`StrictHttpFirewall`提供了一个允许的有效HTTP方法列表,这些方法被允许对[跨站点跟踪](https://owasp.org/www-community/attacks/Cross_Site_Tracing)和[HTTP动词篡改](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/02-Configuration_and_Deployment_Management_Testing/06-Test_HTTP_Methods)进行保护。默认的有效方法是“delete”、“get”、“head”、“options”、“patch”、“post”和“put”。如果你的应用程序需要修改有效的方法,你可以配置一个自定义的`StrictHttpFirewall` Bean。例如,以下将只允许HTTP“get”和“postmethod”方法: + +例2.只允许get和post(P) + +Java + +``` +@Bean +public StrictHttpFirewall httpFirewall() { + StrictHttpFirewall firewall = new StrictHttpFirewall(); + firewall.setAllowedHttpMethods(Arrays.asList("GET", "POST")); + return firewall; +} +``` + +XML + +``` + + + +``` + +Kotlin + +``` +@Bean +fun httpFirewall(): StrictHttpFirewall { + val firewall = StrictHttpFirewall() + firewall.setAllowedHttpMethods(listOf("GET", "POST")) + return firewall +} +``` + +| |如果你正在使用`new MockHttpServletRequest()`,则它当前将创建一个HTTP方法作为空字符串“。
这是一个无效的HTTP方法,并且将被 Spring Security拒绝。
你可以通过将其替换为`new MockHttpServletRequest("GET", "")`来解决此问题。
有关请求改进此问题的请参见[SPR\_16851](https://jira.spring.io/browse/SPR-16851)。| +|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +如果必须允许任何HTTP方法(不推荐),则可以使用`StrictHttpFirewall.setUnsafeAllowAnyHttpMethod(true)`。这将完全禁用HTTP方法的验证。 + +`StrictHttpFirewall`还检查头名称、值和参数名称。它要求每个字符都有一个定义的代码点,而不是一个控制字符。 + +可以使用以下方法根据需要放松或调整此要求: + +* `StrictHttpFirewall#setAllowedHeaderNames(Predicate)` + +* `StrictHttpFirewall#setAllowedHeaderValues(Predicate)` + +* `StrictHttpFirewall#setAllowedParameterNames(Predicate)` + +| |而且,参数值可以用`setAllowedParameterValues(Predicate)`来控制。| +|---|-------------------------------------------------------------------------------------| + +例如,要关闭此检查,你可以将你的`StrictHttpFirewall`与始终返回`Predicate`的`true`连接起来,如: + +例3.允许任何头名称、头值和参数名称 + +Java + +``` +@Bean +public StrictHttpFirewall httpFirewall() { + StrictHttpFirewall firewall = new StrictHttpFirewall(); + firewall.setAllowedHeaderNames((header) -> true); + firewall.setAllowedHeaderValues((header) -> true); + firewall.setAllowedParameterNames((parameter) -> true); + return firewall; +} +``` + +Kotlin + +``` +@Bean +fun httpFirewall(): StrictHttpFirewall { + val firewall = StrictHttpFirewall() + firewall.setAllowedHeaderNames { true } + firewall.setAllowedHeaderValues { true } + firewall.setAllowedParameterNames { true } + return firewall +} +``` + +或者,你可能需要允许一个特定的值。 + +例如,iPhone X使用`User-Agent`,其中包含一个不在ISO-8859-1字符集中的字符。由于这一事实,一些应用程序服务器将把这个值解析为两个单独的字符,后者是一个未定义的字符。 + +你可以使用`setAllowedHeaderValues`方法来解决这个问题,如下所示: + +例4.允许某些用户代理 + +Java + +``` +@Bean +public StrictHttpFirewall httpFirewall() { + StrictHttpFirewall firewall = new StrictHttpFirewall(); + Pattern allowed = Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]]*"); + Pattern userAgent = ...; + firewall.setAllowedHeaderValues((header) -> allowed.matcher(header).matches() || userAgent.matcher(header).matches()); + return firewall; +} +``` + +Kotlin + +``` +@Bean +fun httpFirewall(): StrictHttpFirewall { + val firewall = StrictHttpFirewall() + val allowed = Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]]*") + val userAgent = Pattern.compile(...) + firewall.setAllowedHeaderValues { allowed.matcher(it).matches() || userAgent.matcher(it).matches() } + return firewall +} +``` + +对于标头值,你可以考虑在验证时将它们解析为UTF-8,如下所示: + +例5.将标题解析为UTF-8 + +Java + +``` +firewall.setAllowedHeaderValues((header) -> { + String parsed = new String(header.getBytes(ISO_8859_1), UTF_8); + return allowed.matcher(parsed).matches(); +}); +``` + +Kotlin + +``` +firewall.setAllowedHeaderValues { + val parsed = String(header.getBytes(ISO_8859_1), UTF_8) + return allowed.matcher(parsed).matches() +} +``` + +--- + +[1](#_footnoteref_1)。当浏览器不支持cookie并且`jsessionid`参数在分号之后的URL中附加时,你可能已经看到了这种情况。然而,RFC允许在URL的任何路径段中存在这些参数。 + +[2](#_footnoteref_2)。一旦请求离开`FilterChainProxy`,将返回原始值,因此应用程序仍然可用。 + +[3](#_footnoteref_3)。因此,例如,原始请求路径`/secure;hack=1/somefile.html;hack=2`将返回为`/secure/somefile.html`。 + +[HTTP](http.html)[整合](../integrations/index.html) + diff --git a/docs/spring-security/servlet-exploits-headers.md b/docs/spring-security/servlet-exploits-headers.md new file mode 100644 index 0000000000000000000000000000000000000000..1c2187e8073083862f9c4f9c03f4d9a747b3562a --- /dev/null +++ b/docs/spring-security/servlet-exploits-headers.md @@ -0,0 +1,1092 @@ +# 安全HTTP响应标头 + +[安全HTTP响应标头](../../features/exploits/headers.html#headers)可以用来增加Web应用程序的安全性。本节专门讨论基于 Servlet 的对安全HTTP响应头的支持。 + +## 默认安全标头 + +Spring 安全性提供了[默认的安全HTTP响应标头集](../../features/exploits/headers.html#headers-default)以提供安全的默认值。虽然这些标题中的每一个都被认为是最佳实践,但应该注意的是,并不是所有的客户机都使用这些标题,因此鼓励进行额外的测试。 + +你可以自定义特定的标题。例如,假设你希望使用默认值,但不希望为[X-帧-选项](#servlet-headers-frame-options)指定`SAMEORIGIN`。 + +你可以通过以下配置轻松地实现这一点: + +例1.自定义默认安全标头 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends + WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) { + http + // ... + .headers(headers -> headers + .frameOptions(frameOptions -> frameOptions + .sameOrigin() + ) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + // ... + headers { + frameOptions { + sameOrigin = true + } + } + } + } +} +``` + +如果不希望添加默认值,并且希望对应该使用的内容进行显式控制,则可以禁用默认值。下面举例说明: + +如果你使用 Spring Security的配置,以下将只添加[缓存控制](../../features/exploits/headers.html#headers-cache-control)。 + +例2.自定义缓存控制头 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .headers(headers -> headers + // do not use any default headers unless explicitly listed + .defaultsDisabled() + .cacheControl(withDefaults()) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + // ... + headers { + // do not use any default headers unless explicitly listed + defaultsDisabled = true + cacheControl { + } + } + } + } +} +``` + +如果有必要,可以通过以下配置禁用所有HTTP安全响应头: + +例3.禁用所有HTTP安全标头 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .headers(headers -> headers.disable()); + } +} +``` + +XML + +``` + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + // ... + headers { + disable() + } + } + } +} +``` + +## 缓存控制 + +Spring 默认情况下,安全性包括[缓存控制](../../features/exploits/headers.html#headers-cache-control)标头。 + +但是,如果你实际上想要缓存特定的响应,那么你的应用程序可以有选择地调用[HttpServletResponse.setheader(字符串,字符串)](https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String))来覆盖由 Spring Security设置的头。这对于确保CSS、JavaScript和图像等内容被适当地缓存是有用的。 + +当使用 Spring Web MVC时,这通常是在你的配置中完成的。关于如何做到这一点的详细信息可以在 Spring 参考文档的[静态资源](https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources)部分中找到。 + +如果有必要,还可以禁用 Spring Security的缓存控制HTTP响应头。 + +例4.已禁用缓存控制 + +Java + +``` +@Configuration +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) { + http + // ... + .headers(headers -> headers + .cacheControl(cache -> cache.disable()) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + headers { + cacheControl { + disable() + } + } + } + } +} +``` + +## 内容类型选项 + +Spring 默认情况下,安全性包括[内容类型](../../features/exploits/headers.html#headers-content-type-options)标头。但是,你可以通过以下方式禁用它: + +例5.禁用内容类型选项 + +Java + +``` +@Configuration +@EnableWebSecurity +public class WebSecurityConfig extends + WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) { + http + // ... + .headers(headers -> headers + .contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable()) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + headers { + contentTypeOptions { + disable() + } + } + } + } +} +``` + +## + +Spring 默认情况下,Security提供[严格的运输安全](../../features/exploits/headers.html#headers-hsts)头。但是,你可以显式地定制结果。例如,下面是一个显式提供HSTS的示例: + +例6.严格的运输安全 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .headers(headers -> headers + .httpStrictTransportSecurity(hsts -> hsts + .includeSubDomains(true) + .preload(true) + .maxAgeInSeconds(31536000) + ) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + headers { + httpStrictTransportSecurity { + includeSubDomains = true + preload = true + maxAgeInSeconds = 31536000 + } + } + } + } +} +``` + +## + +出于被动的原因, Spring Security为[HTTP公钥固定](../../features/exploits/headers.html#headers-hpkp)提供了 Servlet 支持,但它是[不再推荐](../../features/exploits/headers.html#headers-hpkp-deprecated)。 + +你可以通过以下配置启用HPKP头: + +例7. HTTP公钥固定 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(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=") + ) + ); + } +} +``` + +XML + +``` + + + + + + + d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM= + E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g= + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + headers { + httpPublicKeyPinning { + includeSubDomains = true + reportUri = "https://example.net/pkp-report" + pins = mapOf("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" to "sha256", + "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" to "sha256") + } + } + } + } +} +``` + +## X-帧-选项 + +默认情况下, Spring Security使用[X-帧-选项](../../features/exploits/headers.html#headers-frame-options)禁用在iFrame中的呈现。 + +你可以使用以下方法自定义框架选项,以便在配置中使用相同的原点: + +例8. x-frame-options:SameOrigin + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .headers(headers -> headers + .frameOptions(frameOptions -> frameOptions + .sameOrigin() + ) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + headers { + frameOptions { + sameOrigin = true + } + } + } + } +} +``` + +## X-XSS-保护 + +默认情况下, Spring Security指示浏览器使用\\来阻止反射的XSS攻击。但是,你可以更改此默认值。例如,以下配置指定 Spring 安全性不应再指示浏览器阻止内容: + +例9. X-XSS-保护定制 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .headers(headers -> headers + .xssProtection(xss -> xss + .block(false) + ) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + // ... + http { + headers { + xssProtection { + block = false + } + } + } + } +} +``` + +## + +Spring 默认情况下安全性不添加[内容安全策略](../../features/exploits/headers.html#headers-csp),因为合理的默认情况是不可能在没有上下文的情况下知道应用程序的。Web应用程序作者必须声明安全策略,以强制执行和/或监视受保护的资源。 + +例如,给出以下安全策略: + +例10.内容安全策略示例 + +``` +Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/ +``` + +你可以启用CSP报头,如下所示: + +例11.内容安全策略 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) { + 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/") + ) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + // ... + headers { + contentSecurityPolicy { + policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" + } + } + } + } +} +``` + +要启用CSP`report-only`头,请提供以下配置: + +例12.仅提供内容安全策略报告 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends + WebSecurityConfigurerAdapter { + + @Override + protected void configure(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() + ) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + 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 默认情况下,安全性不添加[推荐人政策](../../features/exploits/headers.html#headers-referrer)标头。你可以使用如下所示的配置启用Referrer策略标头: + +例13.推荐人政策 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) { + http + // ... + .headers(headers -> headers + .referrerPolicy(referrer -> referrer + .policy(ReferrerPolicy.SAME_ORIGIN) + ) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + // ... + headers { + referrerPolicy { + policy = ReferrerPolicy.SAME_ORIGIN + } + } + } + } +} +``` + +## 特征策略 + +Spring 默认情况下,安全性不添加[特征策略](../../features/exploits/headers.html#headers-feature)头。以下`Feature-Policy`标题: + +例14.功能策略示例 + +``` +Feature-Policy: geolocation 'self' +``` + +可以使用如下所示的配置启用功能策略标头: + +例15.特征-策略 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .headers(headers -> headers + .featurePolicy("geolocation 'self'") + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + // ... + headers { + featurePolicy("geolocation 'self'") + } + } + } +} +``` + +## 权限策略 + +Spring 默认情况下,安全性不添加[权限策略](../../features/exploits/headers.html#headers-permissions)标头。以下`Permissions-Policy`标题: + +例16.权限-策略示例 + +``` +Permissions-Policy: geolocation=(self) +``` + +可以使用如下所示的配置启用权限策略标头: + +例17.权限-策略 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .headers(headers -> headers + .permissionsPolicy(permissions -> permissions + .policy("geolocation=(self)") + ) + ); + } +} +``` + +XML + +``` + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + // ... + headers { + permissionPolicy { + policy = "geolocation=(self)" + } + } + } + } +} +``` + +## 清除站点数据 + +Spring 默认情况下,安全性不添加[清除站点数据](../../features/exploits/headers.html#headers-clear-site-data)头。以下Clear-Site-Data报头: + +例18.清除站点数据示例 + +``` +Clear-Site-Data: "cache", "cookies" +``` + +可以通过以下配置在注销时发送: + +例19.清除站点数据 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .logout() + .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES))); + } +} +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + // ... + logout { + addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(CACHE, COOKIES))) + } + } + } +} +``` + +## 自定义标头 + +Spring 安全性有一些机制,以使其方便地将更常见的安全性标题添加到你的应用程序中。然而,它也提供了钩子来支持添加自定义头。 + +### 静态标头 + +有时,你可能希望将自定义的安全标头插入到你的应用程序中,而这些标头不受开箱即用的支持。例如,给出以下自定义安全标头: + +``` +X-Custom-Security-Header: header-value +``` + +可以使用以下配置将标头添加到响应中: + +例20. Staticheaderswriter + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .headers(headers -> headers + .addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value")) + ); + } +} +``` + +XML + +``` + + + + +
+ + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + // ... + headers { + addHeaderWriter(StaticHeadersWriter("X-Custom-Security-Header","header-value")) + } + } + } +} +``` + +### Headers Writer + +当名称空间或 Java 配置不支持所需的标题时,可以创建自定义`HeadersWriter`实例,甚至提供`HeadersWriter`的自定义实现。 + +让我们来看一个使用`XFrameOptionsHeaderWriter`自定义实例的示例。如果要显式配置[X-帧-选项](#servlet-headers-frame-options),可以通过以下配置完成: + +例21. Headers Writer + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // ... + .headers(headers -> headers + .addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN)) + ); + } +} +``` + +XML + +``` + + + + +
+ + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + // ... + headers { + addHeaderWriter(XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN)) + } + } + } +} +``` + +### 委托请求者headerwriter + +有时,你可能只想为某些请求写一个头。例如,你可能只想保护你的登录页面不被框起来。你可以使用`DelegatingRequestMatcherHeaderWriter`来执行此操作。 + +在 Java 配置中使用`DelegatingRequestMatcherHeaderWriter`的示例如下所示: + +例22.授权请求MatcherHeaderWriter Java 配置 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends +WebSecurityConfigurerAdapter { + + @Override + protected void configure(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) + ); + } +} +``` + +XML + +``` + + + + + +
+ + + + + + + + + + + +``` + +Kotlin + +``` +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + val matcher: RequestMatcher = AntPathRequestMatcher("/login") + val headerWriter = DelegatingRequestMatcherHeaderWriter(matcher, XFrameOptionsHeaderWriter()) + http { + headers { + frameOptions { + disable() + } + addHeaderWriter(headerWriter) + } + } + } +} +``` + +[Cross Site Request Forgery (CSRF) for Servlet Environments](csrf.html)[HTTP](http.html) + diff --git a/docs/spring-security/servlet-exploits-http.md b/docs/spring-security/servlet-exploits-http.md new file mode 100644 index 0000000000000000000000000000000000000000..f911db890b7926051ce7c976c2261680c4cfe36b --- /dev/null +++ b/docs/spring-security/servlet-exploits-http.md @@ -0,0 +1,72 @@ +# HTTP + +所有基于HTTP的通信都应该受到保护[using TLS](../../features/exploits/http.html#http)。 + +下面你可以找到有关 Servlet 特定特性的详细信息,这些特性有助于HTTPS的使用。 + +## 重定向到HTTPS + +如果客户机使用HTTP而不是HTTPS发出请求,则可以将安全性配置为重定向到HTTPS。 + +例如,以下 Java 配置将把任何HTTP请求重定向到HTTPS: + +例1.重定向到HTTPS + +Java + +``` +@Configuration +@EnableWebSecurity +public class WebSecurityConfig extends + WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) { + http + // ... + .requiresChannel(channel -> channel + .anyRequest().requiresSecure() + ); + } +} +``` + +Kotlin + +``` +@Configuration +@EnableWebSecurity +class SecurityConfig : WebSecurityConfigurerAdapter() { + + override fun configure(http: HttpSecurity) { + http { + // ... + requiresChannel { + secure(AnyRequestMatcher.INSTANCE, "REQUIRES_SECURE_CHANNEL") + } + } + } +} +``` + +下面的XML配置将把所有HTTP请求重定向到HTTPS + +例2.使用XML配置重定向到HTTPS + +``` + + +... + +``` + +## 严格的运输安全 + +Spring 安全性为[严格的运输安全](headers.html#servlet-headers-hsts)提供支持,并在默认情况下启用它。 + +## 代理服务器配置 + +Spring 安全性[与代理服务器集成](../../features/exploits/http.html#http-proxy-server)。 + +[安全HTTP响应标头](headers.html)[HttpFirewall ](firewall.html) + diff --git a/docs/spring-security/servlet-exploits.md b/docs/spring-security/servlet-exploits.md new file mode 100644 index 0000000000000000000000000000000000000000..d1ab8d1100948c4552e6b854577668ee436f4862 --- /dev/null +++ b/docs/spring-security/servlet-exploits.md @@ -0,0 +1,13 @@ +# 保护免受剥削 + +本节讨论 Servlet 对[Spring Security’s protection against common exploits](../../features/exploits/index.html#exploits)的特定支持。 + +## 章节摘要 + +* [Cross Site Request Forgery (CSRF) for Servlet Environments](csrf.html) +* [安全HTTP响应标头](headers.html) +* [HTTP](http.html) +* [HttpFirewall](firewall.html) + +[SAML2元数据](../saml2/metadata.html)[Cross Site Request Forgery (CSRF) for Servlet Environments](csrf.html) + diff --git a/docs/spring-security/servlet-getting-started.md b/docs/spring-security/servlet-getting-started.md new file mode 100644 index 0000000000000000000000000000000000000000..8b6bd17761f50866a2420707f7b63ec499a07526 --- /dev/null +++ b/docs/spring-security/servlet-getting-started.md @@ -0,0 +1,79 @@ +# 你好 Spring 安全 + +本节介绍了如何在 Spring 引导中使用 Spring 安全性的最小设置。 + +| |可以找到已完成的应用程序[在我们的样品库中](https://github.com/spring-projects/spring-security-samples/tree/5.6.x/servlet/spring-boot/java/hello-security)。
为了你的方便,你可以通过[点击这里](https://start.spring.io/starter.zip?type=maven-project&language=java&packaging=jar&jvmVersion=1.8&groupId=example&artifactId=hello-security&name=hello-security&description=Hello%20Security&packageName=example.hello-security&dependencies=web,security)下载一个最小的 Spring 引导+ Spring 安全应用程序。| +|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +## 更新依赖项 + +你需要做的唯一一步是通过使用[Maven](../getting-spring-security.html#getting-maven-boot)或[Gradle](../getting-spring-security.html#getting-gradle-boot)更新依赖关系。 + +## 启动Hello Spring 安全启动 + +现在,你可以通过使用 Maven 插件的`run`目标[run the Spring Boot application](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-running-with-the-maven-plugin)。下面的示例展示了如何这样做(以及这样做产生的输出的开始): + +例1.运行 Spring 启动应用程序 + +``` +$ ./mvn spring-boot:run +... +INFO 23689 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration : + +Using generated security password: 8e557245-73e2-4286-969a-ff57fe326336 + +... +``` + +## Spring 引导自动配置 + +Spring 自动启动: + +* 启用 Spring Security的默认配置,该配置将创建 Servlet `Filter`作为名为`springSecurityFilterChain`的 Bean。此 Bean 负责应用程序内的所有安全性(保护应用程序的URL、验证提交的用户名和密码、重定向到表单中的日志,等等)。 + +* 创建一个`UserDetailsService` Bean,其用户名为`user`,并随机生成一个登录到控制台的密码。 + +* 对于每个请求,用名为`springSecurityFilterChain`的 Bean 容器注册`Filter`。 + +Spring Boot的配置不是很多,但它做了很多。以下是这些特征的摘要: + +* 与应用程序的任何交互都需要经过身份验证的用户。 + +* 为你生成默认的登录表单 + +* 让用户名为`user`且密码已登录到控制台的用户使用基于表单的身份验证进行身份验证(在前面的示例中,密码为`8e557245-73e2-4286-969a-ff57fe326336`) + +* 使用bcrypt保护密码存储 + +* 让用户注销 + +* [CSRF攻击](https://en.wikipedia.org/wiki/Cross-site_request_forgery)预防 + +* [Session Fixation](https://en.wikipedia.org/wiki/Session_fixation)保护 + +* 安全报头集成 + + * [HTTP严格的传输安全](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security)用于安全请求 + + * [X-Content-Type-Options](https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).ASPX)积分 + + * 缓存控制(可以稍后由应用程序重写,以允许缓存静态资源) + + * [X-XSS-保护](https://msdn.microsoft.com/en-us/library/dd565647(v=vs.85).ASPX)积分 + + * x-frame-options集成,帮助防止[点击劫持](https://en.wikipedia.org/wiki/Clickjacking) + +* 与以下 Servlet API方法集成: + + * [`HttpServletRequest#getRemoteUser()`](https://DOCS.oracle.com/javaee/6/api/javax/ Servlet/http/httpservletrequest.html#getremoteuser()) + + * [`HttpServletRequest.html#getUserPrincipal()`](https://DOCS.oracle.com/javaee/6/api/javax/ Servlet/http/httpservletrequest.html#getUserprincipal()) + + * [`HttpServletRequest.html#isUserInRole(java.lang.String)`](https://DOCS.oracle.com/javaee/6/api/javax/ Servlet/http/httpservletrequest.html#isuserinrole( Java.lang.string)) + + * [`HttpServletRequest.html#login(java.lang.String, java.lang.String)`](https://DOCS.oracle.com/javaee/6/api/javax/ Servlet/http/httpservletrequest.html#login( Java.lang.string,%20java.lang.string)) + + * [`HttpServletRequest.html#logout()`](https://DOCS.oracle.com/javaee/6/api/javax/ Servlet/http/httpservletrequest.html#logout()) + +[Servlet Applications](index.html)[建筑](architecture.html) + diff --git a/docs/spring-security/servlet-integrations-concurrency.md b/docs/spring-security/servlet-integrations-concurrency.md new file mode 100644 index 0000000000000000000000000000000000000000..14eba18adad2d921aa9eb2240b8040c531ab407e --- /dev/null +++ b/docs/spring-security/servlet-integrations-concurrency.md @@ -0,0 +1,146 @@ +# 并发支持 + +在大多数环境中,安全性是以per`Thread`为基础存储的。这意味着,当在新的`Thread`上完成工作时,`SecurityContext`将丢失。 Spring 安全性提供了一些基础设施,以帮助用户更容易地实现这一点。 Spring 安全性为在多线程环境中使用 Spring 安全性提供了低层次的抽象。实际上,这是 Spring 安全性构建在[`AsyncContext.start(Runnable)`]( Servlet-api.html#servletapi-start-runnable)和[Spring MVC Async Integration](mvc.html#mvc-async)集成之上的。 + +## 在可撤销的情况下将证券转让 + +Spring Security的并发支持中最基本的构建块之一是`DelegatingSecurityContextRunnable`。它包装了一个委托`Runnable`,以便用指定的`SecurityContext`为委托初始化`SecurityContextHolder`。然后,它调用委托Runnable确保在之后清除`SecurityContextHolder`。`DelegatingSecurityContextRunnable`看起来是这样的: + +``` +public void run() { +try { + SecurityContextHolder.setContext(securityContext); + delegate.run(); +} finally { + SecurityContextHolder.clearContext(); +} +} +``` + +虽然非常简单,但它可以无缝地将SecurityContext从一个线程转移到另一个线程。这一点很重要,因为在大多数情况下,SecurityContextholder是以每个线程为基础的。例如,你可能使用了 Spring Security的[``](../acception/namespace/method-security.html#NSA-global-method-security)支持来保护你的某个服务。现在,你可以轻松地将当前`Thread`的`SecurityContext`传输到调用安全服务的`Thread`。下面是你如何做到这一点的一个示例: + +``` +Runnable originalRunnable = new Runnable() { +public void run() { + // invoke secured service +} +}; + +SecurityContext context = SecurityContextHolder.getContext(); +DelegatingSecurityContextRunnable wrappedRunnable = + new DelegatingSecurityContextRunnable(originalRunnable, context); + +new Thread(wrappedRunnable).start(); +``` + +上面的代码执行以下步骤: + +* 创建将调用我们的安全服务的`Runnable`。请注意,它并不了解 Spring 安全性 + +* 从`SecurityContextHolder`获取我们希望使用的`SecurityContext`,并初始化`DelegatingSecurityContextRunnable` + +* 使用`DelegatingSecurityContextRunnable`创建线程 + +* 启动我们创建的线程 + +由于从`SecurityContextHolder`中使用`SecurityContext`创建`DelegatingSecurityContextRunnable`是很常见的,因此有一个用于它的快捷构造函数。以下代码与上述代码相同: + +``` +Runnable originalRunnable = new Runnable() { +public void run() { + // invoke secured service +} +}; + +DelegatingSecurityContextRunnable wrappedRunnable = + new DelegatingSecurityContextRunnable(originalRunnable); + +new Thread(wrappedRunnable).start(); +``` + +我们拥有的代码使用起来很简单,但仍然需要了解我们正在使用 Spring 安全性。在下一节中,我们将研究如何利用`委派安全环境专家`来隐藏我们正在使用 Spring 安全性的事实。 + +## DelegatingSecurityContextExecutor + +在上一节中,我们发现使用`DelegatingSecurityContextRunnable`很容易,但并不理想,因为我们必须意识到 Spring 安全性才能使用它。让我们来看看`DelegatingSecurityContextExecutor`如何保护我们的代码不受我们正在使用 Spring 安全性的任何知识的影响。 + +`DelegatingSecurityContextExecutor`的设计与`DelegatingSecurityContextRunnable`的设计非常相似,只是它接受一个委托`Executor`而不是一个委托`Runnable`。你可以在下面看到一个如何使用它的示例: + +``` +SecurityContext context = SecurityContextHolder.createEmptyContext(); +Authentication authentication = + new UsernamePasswordAuthenticationToken("user","doesnotmatter", AuthorityUtils.createAuthorityList("ROLE_USER")); +context.setAuthentication(authentication); + +SimpleAsyncTaskExecutor delegateExecutor = + new SimpleAsyncTaskExecutor(); +DelegatingSecurityContextExecutor executor = + new DelegatingSecurityContextExecutor(delegateExecutor, context); + +Runnable originalRunnable = new Runnable() { +public void run() { + // invoke secured service +} +}; + +executor.execute(originalRunnable); +``` + +代码执行以下步骤: + +* 创建用于我们的`DelegatingSecurityContextExecutor`的`SecurityContext`。注意,在这个示例中,我们只需手工创建`SecurityContext`。然而,无论我们在哪里或如何获得`SecurityContext`都不重要(也就是说,如果我们愿意,我们可以从`SecurityContextHolder`获得它)。 + +* 创建一个DelegateExecutor,它负责执行提交的`Runnable`s + +* 最后,我们创建一个`DelegatingSecurityContextExecutor`,它负责用`DelegatingSecurityContextRunnable`包装传递到Execute方法中的任何runnable。然后,它将包装好的Runnable传递给DelegateExecutor。在此实例中,对于提交到我们的`DelegatingSecurityContextExecutor`的每个runnable,将使用相同的`SecurityContext`。如果我们运行的是需要由具有提升权限的用户运行的后台任务,那么这很好。 + +* 此时,你可能会问自己:“这是如何保护我的代码不受安全知识的影响的?”我们不需要在自己的代码中创建`SecurityContext`和`DelegatingSecurityContextExecutor`,而是可以插入一个已经初始化的`DelegatingSecurityContextExecutor`实例。 + +``` +@Autowired +private Executor executor; // becomes an instance of our DelegatingSecurityContextExecutor + +public void submitRunnable() { +Runnable originalRunnable = new Runnable() { + public void run() { + // invoke secured service + } +}; +executor.execute(originalRunnable); +} +``` + +现在我们的代码不知道`SecurityContext`正在传播到`Thread`,然后运行`originalRunnable`,然后清除`SecurityContextHolder`。在本例中,使用相同的用户运行每个线程。如果我们希望在调用`SecurityContextHolder`时使用来自`executor.execute(Runnable)`的用户(即当前登录的用户)来处理`originalRunnable`,该怎么办?这可以通过从我们的`DelegatingSecurityContextExecutor`构造函数中删除`SecurityContext`参数来完成。例如: + +``` +SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor(); +DelegatingSecurityContextExecutor executor = + new DelegatingSecurityContextExecutor(delegateExecutor); +``` + +现在,每当执行`executor.execute(Runnable)`时,`SecurityContext`首先由`SecurityContextHolder`得到,然后`SecurityContext`用于创建我们的`DelegatingSecurityContextRunnable`。这意味着我们运行`Runnable`的用户与调用`executor.execute(Runnable)`代码的用户相同。 + +## Spring 安全并发类 + +请参考Javadoc,以获取与 Java 并发API和 Spring 任务抽象的附加集成。一旦你理解了前面的代码,它们就非常不言自明了。 + +* `DelegatingSecurityContextCallable` + +* `DelegatingSecurityContextExecutor` + +* `DelegatingSecurityContextExecutorService` + +* `DelegatingSecurityContextRunnable` + +* `DelegatingSecurityContextScheduledExecutorService` + +* `DelegatingSecurityContextSchedulingTaskExecutor` + +* `DelegatingSecurityContextAsyncTaskExecutor` + +* `DelegatingSecurityContextTaskExecutor` + +* `DelegatingSecurityContextTaskScheduler` + +[整合](index.html)[Jackson](jackson.html) + diff --git a/docs/spring-security/servlet-integrations-cors.md b/docs/spring-security/servlet-integrations-cors.md new file mode 100644 index 0000000000000000000000000000000000000000..301bd5b1fde2ca598a7b66e932ec5f652e39c855 --- /dev/null +++ b/docs/spring-security/servlet-integrations-cors.md @@ -0,0 +1,116 @@ +# CORS + +Spring Framework提供[CORS的一流支持](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors)。CORS必须在 Spring 安全性之前进行处理,因为飞行前请求将不包含任何cookie(即`JSESSIONID`)。如果请求不包含任何cookie并且 Spring 安全性是第一位的,则该请求将确定用户未经过身份验证(因为在该请求中没有cookie)并拒绝它。 + +确保先处理CORS的最简单方法是使用`CorsFilter`。用户可以通过以下方式提供`CorsConfigurationSource`,将`CorsFilter`与 Spring 安全性集成在一起: + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // by default uses a Bean by the name of corsConfigurationSource + .cors(withDefaults()) + ... + } + + @Bean + CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins(Arrays.asList("https://example.com")); + configuration.setAllowedMethods(Arrays.asList("GET","POST")); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } +} +``` + +Kotlin + +``` +@EnableWebSecurity +open class WebSecurityConfig : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + // by default uses a Bean by the name of corsConfigurationSource + cors { } + // ... + } + } + + @Bean + open fun corsConfigurationSource(): CorsConfigurationSource { + val configuration = CorsConfiguration() + configuration.allowedOrigins = listOf("https://example.com") + configuration.allowedMethods = listOf("GET", "POST") + val source = UrlBasedCorsConfigurationSource() + source.registerCorsConfiguration("/**", configuration) + return source + } +} +``` + +或在XML中 + +``` + + + ... + + + ... + +``` + +如果使用 Spring MVC的CORS支持,则可以省略指定`CorsConfigurationSource`,并且 Spring Security将利用提供给 Spring MVC的CORS配置。 + +Java + +``` +@EnableWebSecurity +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // if Spring MVC is on classpath and no CorsConfigurationSource is provided, + // Spring Security will use CORS configuration provided to Spring MVC + .cors(withDefaults()) + ... + } +} +``` + +Kotlin + +``` +@EnableWebSecurity +open class WebSecurityConfig : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + // if Spring MVC is on classpath and no CorsConfigurationSource is provided, + // Spring Security will use CORS configuration provided to Spring MVC + cors { } + // ... + } + } +} +``` + +或在XML中 + +``` + + + + ... + +``` + +[WebSocket](websocket.html)[JSP Taglib](jsp-taglibs.html) + diff --git a/docs/spring-security/servlet-integrations-data.md b/docs/spring-security/servlet-integrations-data.md new file mode 100644 index 0000000000000000000000000000000000000000..cc57ad3eca7476b4cf87feb1439c2a8f3e8cfeb6 --- /dev/null +++ b/docs/spring-security/servlet-integrations-data.md @@ -0,0 +1,59 @@ +# Spring 数据集成 + +Spring 安全性提供了 Spring 数据集成,允许在查询中引用当前用户。将用户包括在查询中以支持分页结果不仅是有用的,而且是必要的,因为在此之后对结果进行过滤将不会扩展。 + +## Spring 数据和 Spring 安全配置 + +要使用此支持,请添加`org.springframework.security:spring-security-data`依赖项,并提供`SecurityEvaluationContextExtension`类型的 Bean: + +Java + +``` +@Bean +public SecurityEvaluationContextExtension securityEvaluationContextExtension() { + return new SecurityEvaluationContextExtension(); +} +``` + +Kotlin + +``` +@Bean +fun securityEvaluationContextExtension(): SecurityEvaluationContextExtension { + return SecurityEvaluationContextExtension() +} +``` + +在XML配置中,这看起来像是: + +``` + +``` + +## @query中的安全表达式 + +现在,安全性可以在查询中使用。例如: + +Java + +``` +@Repository +public interface MessageRepository extends PagingAndSortingRepository { + @Query("select m from Message m where m.to.id = ?#{ principal?.id }") + Page findInbox(Pageable pageable); +} +``` + +Kotlin + +``` +@Repository +interface MessageRepository : PagingAndSortingRepository { + @Query("select m from Message m where m.to.id = ?#{ principal?.id }") + fun findInbox(pageable: Pageable): Page +} +``` + +这将检查`Authentication.getPrincipal().getId()`是否等于`Message`的接收者。请注意,本例假定你已将主体自定义为具有ID属性的对象。通过公开`SecurityEvaluationContextExtension` Bean,查询中的所有[常见的安全表达式](../authorization/expression-based.html#common-expressions)都是可用的。 + +[Servlet APIs](servlet-api.html)[Spring MVC](mvc.html) \ No newline at end of file diff --git a/docs/spring-security/servlet-integrations-jackson.md b/docs/spring-security/servlet-integrations-jackson.md new file mode 100644 index 0000000000000000000000000000000000000000..05b721efb63bfa670efdbaa90aeb5f36fda57958 --- /dev/null +++ b/docs/spring-security/servlet-integrations-jackson.md @@ -0,0 +1,23 @@ +# Jackson支助 + +Spring 安全性为持久化 Spring 与安全性相关的类提供了Jackson支持。这可以在使用分布式会话(即会话复制、 Spring 会话等)时提高序列化 Spring 安全相关类的性能。 + +要使用它,将`SecurityJackson2Modules.getModules(ClassLoader)`注册为`ObjectMapper`([Jackson-数据库](https://github.com/FasterXML/jackson-databind)): + +``` +ObjectMapper mapper = new ObjectMapper(); +ClassLoader loader = getClass().getClassLoader(); +List modules = SecurityJackson2Modules.getModules(loader); +mapper.registerModules(modules); + +// ... use ObjectMapper as normally ... +SecurityContext context = new SecurityContextImpl(); +// ... +String json = mapper.writeValueAsString(context); +``` + +| |以下 Spring 安全模块提供了Jackson支持:

* Spring-security-core(`CoreJackson2Module`)

* Spring-security-web(`WebJackson2Module`,`WebServletJackson2Module`,`WebServerJackson2Module`)
(<11"gt="9"/>r=“r=”/>(<18"r="19"r=">>>>>(<<<<>>>>>| +|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +[并发性](concurrency.html)[本地化](localization.html) + diff --git a/docs/spring-security/servlet-integrations-jsp-taglibs.md b/docs/spring-security/servlet-integrations-jsp-taglibs.md new file mode 100644 index 0000000000000000000000000000000000000000..50ab01d8767cddf31107d2863195e6fa02f248a8 --- /dev/null +++ b/docs/spring-security/servlet-integrations-jsp-taglibs.md @@ -0,0 +1,163 @@ +# JSP标记库 + +## 宣布Taglib + +要使用任何标记,你必须在JSP中声明安全性taglib: + +``` +<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> +``` + +## 授权标签 + +此标记用于确定是否应该对其内容进行评估。在 Spring Security3.0中,可以用两种方式[1]。第一种方法使用[Web安全表达式](../authorization/expression-based.html#el-access-web),在标记的`access`属性中指定。表达式求值将委托给在应用程序上下文中定义的`SecurityExpressionHandler`(你应该在``名称空间配置中启用Web表达式,以确保此服务可用)。所以,举个例子,你可能 + +``` + + +This content will only be visible to users who have the "supervisor" authority in their list of GrantedAuthoritys. + + +``` + +当与 Spring Security的PermissionEvaluator结合使用时,该标记还可以用于检查权限。例如: + +``` + + +This content will only be visible to users who have read or write permission to the Object found as a request attribute named "domain". + + +``` + +一个常见的要求是只显示一个特定的链接,如果用户实际上被允许单击它的话。我们怎样才能事先确定某件事是否会被允许?这个标记也可以在另一种模式下操作,这种模式允许你将特定的URL定义为一个属性。如果允许用户调用该URL,则将计算标记主体,否则将跳过该标记主体。所以你可能会有一些类似的东西 + +``` + + +This content will only be visible to users who are authorized to send requests to the "/admin" URL. + + +``` + +要使用此标记,还必须在应用程序上下文中有`WebInvocationPrivilegeEvaluator`的实例。如果使用名称空间,将自动注册一个名称空间。这是`DefaultWebInvocationPrivilegeEvaluator`的一个实例,该实例为提供的URL创建一个虚拟Web请求,并调用安全拦截器查看请求是成功还是失败。这允许你委派到使用``命名空间配置中的`intercept-url`声明定义的访问控制设置,并节省了在JSP中复制信息(例如所需的角色)的时间。这种方法还可以与`method`属性结合,提供HTTP方法,以进行更具体的匹配。 + +通过将`var`属性设置为变量名,可以将计算标记(无论是授予还是拒绝访问)的布尔结果存储在页面上下文范围变量中,从而避免了在页面的其他点重复和重新计算条件的需要。 + +### 禁用标记授权以进行测试 + +在页面中为未经授权的用户隐藏链接并不会阻止他们访问该URL。例如,他们可以直接在浏览器中输入。作为测试过程的一部分,你可能想要显示隐藏的区域,以检查链接是否真的在后端得到了保护。如果将系统属性`spring.security.disableUISecurity`设置为`true`,则`authorize`标记仍将运行,但不会隐藏其内容。默认情况下,它还会用`…​`标记包围内容。这允许你以特定的CSS样式(例如不同的背景颜色)显示“隐藏”内容。例如,尝试在启用此属性的情况下运行“tutorial”示例应用程序。 + +如果你想从默认的`span`标记中更改周围的文本(或使用空字符串完全删除它),还可以设置属性`spring.security.securedUIPrefix`和`spring.security.securedUISuffix`。 + +## 身份验证标记 + +此标记允许访问存储在安全上下文中的当前`Authentication`对象。它在JSP中直接呈现对象的属性。因此,例如,如果`Authentication`的`principal`属性是 Spring Security的`UserDetails`对象的实例,那么使用``将呈现当前用户的名称。 + +当然,在这种情况下没有必要使用JSP标记,有些人更喜欢在视图中尽可能少地保留逻辑。你可以访问MVC控制器中的`Authentication`对象(通过调用`SecurityContextHolder.getContext().getAuthentication()`),并将数据直接添加到模型中,以便由视图进行呈现。 + +## AccessControlist标签 + +此标记仅在与 Spring Security的ACL模块一起使用时有效。它检查指定域对象所需权限的逗号分隔列表。如果当前用户拥有所有这些权限,那么将对标记主体进行评估。如果他们不这么做,就会被跳过。一个例子可能是 + +| |一般来说,这个标记应该被认为是废弃的。
而不是使用[授权标签](#taglibs-authorize)。| +|---|-----------------------------------------------------------------------------------------------------------------| + +``` + + +This will be shown if the user has all of the permissions represented by the values "1" or "2" on the given object. + + +``` + +这些权限被传递给在应用程序上下文中定义的`PermissionFactory`,将它们转换为ACL`Permission`实例,因此它们可以是工厂支持的任何格式-它们不必是整数,它们可以是`READ`或`WRITE`之类的字符串。如果没有找到`PermissionFactory`,将使用`DefaultPermissionFactory`的实例。应用程序上下文中的`AclService`将用于为所提供的对象加载`Acl`实例。将使用所需的权限调用`Acl`,以检查是否已授予所有权限。 + +该标记还支持`var`属性,与`authorize`标记的方式相同。 + +## csrfinput标记 + +如果启用了CSRF保护,则此标记将插入一个隐藏的表单字段,其中包含CSRF保护令牌的正确名称和值。如果未启用CSRF保护,则此标记不输出任何内容。 + +Spring 通常情况下,Security会自动为你使用的任何``标记插入一个CSRF窗体字段,但是如果由于某种原因你无法使用``,`csrfInput`是一个方便的替换。 + +你应该将此标记放置在HTML``块中,在该块中你通常会放置其他输入字段。不要将此标记放置在 Spring ``块中。 Spring 安全自动处理 Spring 表单。 + +``` +
+ + Name:
+ + ... + +``` + +## CSRFmetatags标签 + +如果启用了CSRF保护,则此标记将插入包含CSRF保护令牌窗体域和头名称以及CSRF保护令牌值的元标记。这些元标记对于在应用程序的JavaScript中使用CSRF保护非常有用。 + +你应该将`csrfMetaTags`放在HTML``块中,在该块中你通常会放置其他元标记。使用此标记后,就可以使用JavaScript轻松地访问表单字段名、标头名和令牌值。本例中使用了jQuery来简化任务。 + +``` + + + + CSRF Protected JavaScript Page + + +