spring security 概览

高屋建瓴的看一下spring security 在servlet应用中如何认证授权漏洞防护

filter 回顾

spring security 对于servlet应用的支持,主要是通过filter来实现。 回顾一下一个HTTP请求的处理过程:

filterchain

客户端向应用程序发送请求,容器创建一个 FilterChain,其中包含应该根据请求 URI 的路径处理 HttpServletRequest 的 Filters 和 Servlet 。 在 Spring MVC 应中,Servlet 是 DispatcherServlet 的一个实例。一个 HttpServletRequest 和 HttpServletResponse最多只能一个 Servlet 可以处理,但是,可以使用多个过滤器来做以下事情:

  1. 阻止下游过滤器或 Servlet 被调用。在这种情况下,过滤器通常会写入 HttpServletResponse
  2. 修改下游Filters和Servlet使用的HttpServletRequest或HttpServletResponse

Filter是通过传入进来的FilterChain 来实现这种操作的, 由于Filter只能影响下游的Filter和Servlet,所以Filter的顺序非常重要。

DelegatingFilterProxy

spring 提供了一个叫DelegatingFilterProxy的实现, 它有效连通了容器的生命周期和spring 上下文。Servlet 容器允许使用自己的标准注册过滤器,但它不知道 Spring 定义的 Bean。DelegatingFilterProxy 可以通过标准的 Servlet 容器机制注册,但将所有工作委托给实现 FilterSpring Bean

这是 DelegatingFilterProxy 如何适应过滤器和过滤器链的图片

DelegatingFilterProxy

DelegatingFilterProxy ApplicationContext 中查找 Bean Filter0,然后调用 Bean Filter0DelegatingFilterProxy的伪代码如下

1
2
3
4
5
6
7
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// Lazily get Filter that was registered as a Spring Bean
// For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
Filter delegate = getFilterBean(someBeanName);
// delegate work to the Spring Bean
delegate.doFilter(request, response);
}

DelegatingFilterProxy 的另一个好处是它允许延迟查找 Filter bean 实例。这很重要,因为容器需要在容器启动之前注册 Filter 实例。但是,Spring 通常使用 ContextLoaderListener 来加载 Spring Bean,这是在注册 Filter 实例之后才完成的。

FilterChainProxy

Spring Security 的 Servlet 支持包含在 FilterChainProxy 中。FilterChainProxy 就是一实现了Filter的Bean,通过上文提到的DelegatingFilterProxy来使用。它允许通过 SecurityFilterChain 委托给许多 Filter 实例。

FilterChainProxy

SecurityFilterChain

FilterChainProxy 使用 SecurityFilterChain 来确定应为此请求调用哪些 Spring 安全过滤器。

SecurityFilterChain

SecurityFilterChain 中的Security Filters通常是 Bean,但它们注册到 FilterChainProxy 而不是 DelegatingFilterProxy。FilterChainProxy 为直接向 Servlet 容器或 DelegatingFilterProxy 注册提供了许多优势。

首先,它为 Spring Security 的所有 Servlet 支持提供了一个起点。因此,如果您尝试对 Spring Security 的 Servlet 支持进行故障排除,那么在 FilterChainProxy 中添加调试点是一个很好的起点。

其次,由于 FilterChainProxy 是 Spring Security 使用的核心,它可以执行一些必不可少的任务。例如,它清除 SecurityContext 以避免内存泄漏。它还应用 Spring Security 的 HttpFirewall 来保护应用程序免受某些类型的攻击。

此外,它在确定何时应该调用 SecurityFilterChain 方面提供了更大的灵活性。在 Servlet 容器中,仅根据 URL 调用过滤器。但是,FilterChainProxy 可以通过利用 RequestMatcher 接口根据 HttpServletRequest 中的任何内容确定调用。

实际上,FilterChainProxy 可用于确定应使用哪个 SecurityFilterChain。这样就可以为应用程序不同的切片提供完全独立的配置。

Figure 5. Multiple SecurityFilterChain

在 Multiple SecurityFilterChain 图中,FilterChainProxy 决定应该使用哪个 SecurityFilterChain。只会调用匹配的第一个 SecurityFilterChain。如果请求 /api/messages/ 的 URL,它将首先匹配 SecurityFilterChain:0 的 /api/** 模式,因此即使它也匹配 SecurityFilterChain:n,只会调用 SecurityFilterChain:0。如果请求 /messages/ 的 URL,它将与 SecurityFilterChain0 的 /api/** 模式不匹配,因此 FilterChainProxy 将继续尝试每个 SecurityFilterChain。假设没有其他匹配的SecurityFilterChain,那么SecurityFilterChain:n 将被调用。

请注意,SecurityFilterChain:0 仅配置了SecurityFilter实例。但是,SecurityFilterChain:n 配置了四个SecurityFilter。需要注意的是,每个 SecurityFilterChain 都可以是唯一的并且可以单独配置。事实上,如果应用程序希望 Spring Security 忽略某些请求,则 SecurityFilterChain 可能没有SecurityFilter

Security Filters

Security Filters 通过 SecurityFilterChain API 插入到 FilterChainProxy 中。过滤器的顺序很重要。通常不需要知道 Spring Security 过滤器的顺序。不过,有时修改知道顺序也是有好处的。 以下是 Spring Security Filter 的完整顺序:

  • ChannelProcessingFilter
  • ConcurrentSessionFilter
  • WebAsyncManagerIntegrationFilter
  • SecurityContextPersistenceFilter
  • HeaderWriterFilter
  • CorsFilter
  • CsrfFilter
  • LogoutFilter
  • OAuth2AuthorizationRequestRedirectFilter
  • Saml2WebSsoAuthenticationRequestFilter
  • X509AuthenticationFilter
  • AbstractPreAuthenticatedProcessingFilter
  • CasAuthenticationFilter
  • OAuth2LoginAuthenticationFilter
  • Saml2WebSsoAuthenticationFilter
  • UsernamePasswordAuthenticationFilter
  • ConcurrentSessionFilter
  • OpenIDAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • DigestAuthenticationFilter
  • BearerTokenAuthenticationFilter
  • FilterSecurityInterceptor
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • JaasApiIntegrationFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • OAuth2AuthorizationCodeGrantFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • SwitchUserFilter

处理 Security 异常

ExceptionTranslationFilter 允许将 AccessDeniedExceptionAuthenticationException 转换为 HTTP 响应。

ExceptionTranslationFilter 作为安全过滤器之一插入到 FilterChainProxy 中。

img

  1. 首先,ExceptionTranslationFilter 调用 FilterChain.doFilter(request, response) 来调用应用程序的其余部分。

  2. 如果用户未通过身份验证或者是

    1
    AuthenticationException

    ,则启动身份验证流程:

    • 清除SecurityContextHolder
    • HttpServletRequest 保存在 RequestCache 中。当用户认证成功时,RequestCache 用于重放原始请求。
    • AuthenticationEntryPoint 用于从客户端请求凭据。例如,它可能会重定向到登录页面或发送 WWW-Authenticate header。
  3. 如果它是 AccessDeniedException,则拒绝访问。调用 AccessDeniedHandler 来处理拒绝访问。.

注意: 如果应用程序没有抛出 AccessDeniedExceptionAuthenticationException,则 ExceptionTranslationFilter 不会做任何事情。