본문 바로가기

Web/spring

[Spring security] Architecture

728x90

https://docs.spring.io/spring-security/reference/servlet/architecture.html

 

Architecture :: Spring Security

Spring Security’s Servlet support is based on Servlet Filters, so it is helpful to look at the role of Filters generally first. The following image shows the typical layering of the handlers for a single HTTP request. The client sends a request to the ap

docs.spring.io

 

틀린 내용이 있다면 알려주세요, 감사합니다🧐

 


Architecture

 

 

 

A Review of Filters

Spring Security 의 Servlet 지원은 Servlet Filter 을 기반으로 한다

Filter 의 역할을 살펴본다

 

client 가 application 에게 request를 보냈을 때, 컨테이너는 요청한 URI 를 기반으로 두가지를 생성한다.

1. HttpServletRequest를 처리하는 필터 인스턴스와

2. Servlet을 포함하는 FilterChain 

이 두가지이다.

 

Spring MVC 에서 Servlet은 DispatcherServlet의 인스턴스라서 하나의 서플릿이 단일의 HttpServletRequest와 HttpServletResponse 를 처리한다

 

그러나 둘 이상의 필터를 사용하면 다음으로 수행이 가능하다.

 

  • Prevent downstream Filter instances or the Servlet from being invoked. In this case, the Filter typically writes the HttpServletResponse.
  • Modify the HttpServletRequest or HttpServletResponse used by the downstream Filter instances and the Servlet.

1. 호출되지 않게 한다 (invoked) 이는 일반적으로 HttpServletResponse에서 작성된다

2. Downstream Filter instance 및 서블릿에서 사용하는 HttpServletRequest와 HttpServletResponse 를 수정한다

 

 

필터로 걸러서

할지/말지

정해진다는 것이다.

 

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
	// do something before the rest of the application
    chain.doFilter(request, response); // invoke the rest of the application
    // do something after the rest of the application
}

위의 설명 그림처럼

호출되는 순서에 때라 걸러지기 때문에 순서가 매우 중요하다

 

 

 

 

 

DelegatingFilterProxy

Spring 은 여기에서 Servlet Container의 lifecycle과 ApplicationContext 사이를 연결하는 proxy 를 제공하는데

이게 DelegatingFilterProxy 이다

 

ServletContainer는 자체 표준을 사용하여 Filter instances를 등록할 수 있지만 이때 Spring이 정의하는 bean을 인식하지 못한다

표준 ServletContainer 메커니즘을 통해 DelegatingFilterProxy를 등록할 수 있지만 Filter를 구현하고 있는 Spring bean에게 이 작업을 위임하는 것이다.

 

 

DelegatingFilterProxy

DelegatingFilterProxy looks up Bean Filter0 from the ApplicationContext and then invokes Bean Filter0. The following listing shows pseudo code of DelegatingFilterProxy:

 

 

 

- Pseudo Code

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);
}

getFilterBean <<<

 

 

이렇게 하면 중간에 처리가 되니 Filter bean instance 를 찾는 것을 지연시킬 수 있다.

컨테이너가 시작되기 전에 필터가 인스턴스를 등록해야하는데, 이를 저 필터체인 작동 시점에서 가능하다

 

또 알아둬야할 것은 Spring 은 보통 ContextLoaderListener 를 사용하여 Spring Bean을 load gksmsep

이 Filter instance 가 등록된어야 완료가 가능하다

 

 

 

 

FilterChainProxy

Spring Security의 Servlet support 는 FilterChainProxy에 포함되어있다.

FilterChainProxy는 Spring Security에서 제공하는 특수 필터로,

SecurityFilterChain을 통해 Filter Instance 들에게 위임이 가능하다

FilterChainProxy는 Bean 이고, 일반적으로 DelegatingFilterProxy에 래핑된다

 

FilterChainProxy

 

 

 

SecurityFilterChain

SecurityFilterChain 은 FilterChainProxy에서 현재 요청에 대해 어떤 SpringSecurityFilterInstance를 호출해야할지 결정한다

The Security Filters in SecurityFilterChain are typically Beans, but they are registered with FilterChainProxy instead of DelegatingFilterProxy. FilterChainProxy provides a number of advantages to registering directly with the Servlet container or DelegatingFilterProxy. 

SecurityFilterChain의 보안필터는 일반적으로 bean이지만

DelegatingFilterProxy대신 FilterChainProxy에 등록된다

FilterChainProxy는 ServletContainer 또는 DelegatingFilterProxy에 직접 등록할 수 있는 장점을 제공한다

 

First, it provides a starting point for all of Spring Security’s Servlet support. For that reason, if you try to troubleshoot Spring Security’s Servlet support, adding a debug point in FilterChainProxy is a great place to start.

> 모든 서블릿을 위한 시작점을 제공한다, Security 문제 해결 시 디버그 지점으로 추가하는 것이 좋다

Second, since FilterChainProxy is central to Spring Security usage, it can perform tasks that are not viewed as optional. For example, it clears out the SecurityContext to avoid memory leaks. It also applies Spring Security’s HttpFirewall to protect applications against certain types of attacks.

> FilterChainProxy는 Spring Security 사용 중심이기 때문에 선택 사항으로 간주되지 않은 작업 수행이 가능하다.

SecurityContext를 메모리 누수를 방지하기 위해 지울 수 있고, HttpFirewall 을 적용하여 특정 유형 공격으로 부터 애플리케이션을 보호한다

In addition, it provides more flexibility in determining when a SecurityFilterChain should be invoked. In a Servlet container, Filter instances are invoked based upon the URL alone. However, FilterChainProxy can determine invocation based upon anything in the HttpServletRequest by using the RequestMatcher interface.

-> 마지막으로 SecurityFilterChain 호출 시기를 유연하게 할 수 있다.

ServletContainer에서 FilterInstance 는 URL 기준으로만 호출하지만

FilterChainProxy는 RequestMatcher Interface를 사용하여 HttpServletRequest의 모든 항목을 기반으로 호출을 결정할 수 있다.

 

 

 

Multiple SecurityFilterChain

FilterChainProxy decides which SecurityFilterChain should be used. 

Only the first SecurityFilterChain that matches is invoked.

 

If a URL of /api/messages/ is requested,

it first matches on the SecurityFilterChain0 pattern of /api/**, so only SecurityFilterChain0 is invoked, even though it also matches on SecurityFilterChainn.

 

 

If a URL of /messages/ is requested,

it does not match on the SecurityFilterChain0 pattern of /api/**, so FilterChainProxy continues trying each SecurityFilterChain.

Assuming that no other SecurityFilterChain instances match, SecurityFilterChainn is invoked.

 

Notice that SecurityFilterChain0 has only three security Filter instances configured.

 

However, SecurityFilterChainn has four security Filter instanes configured.

It is important to note that each SecurityFilterChain can be unique and can be configured in isolation.

In fact, a SecurityFilterChain might have zero security Filter instances if the application wants Spring Security to ignore certain requests.

 

 

 

Security Filters

보안 필터는 SecurityFilterChain API를 사용 하여 FilterChainProxy에 삽입된다

그래서 순서가 중요하다

 

일반적으로 Filter instnace 순서를 알 필요는 없으나 아는게 좋다 (보라는 거야 말라는 거야 보라는 거겠지..)

 

 

 

대충 어떤 순서로 흘러가는지 읽어만 두면 될 것 같다

The following is a comprehensive list of Spring Security Filter ordering:

 

 

 

Handling Security Exceptions

ExceptionTranslationFilter를 사용하면 AccessDeniedException 및 AuthenticationException을 HTTP 응답으로 변환할 수 있다.

ExceptionTranslationFilter는 보안 필터 중 하나로 FilterChainProxy에 insert 된다.

 

relationship of  ExceptionTranslationFilter  to other component

 

1. ExceptionTranslationFilter invokes FilterChain.doFilter(request, response) to invoke the rest of the application.

2. If the user is not authenticated or it is an AuthenticationException, then Start Authentication.

  • The SecurityContextHolder is cleared out.
  • The HttpServletRequest is saved so that it can be used to replay the original request once authentication is successful.

The AuthenticationEntryPoint is used to request credentials from the client. For example, it might redirect to a log in page or send a WWW-Authenticate header.

3. Otherwise, if it is an AccessDeniedException, then Access Denied. The AccessDeniedHandler is invoked to handle access denied.

 

 

1. ExceptionTranslationFilter 는 FilterChain.doFilter(request, response) 를 호출하여 나머지 애플리케이션을 호출한다

2. 사용자가 인증되지 않았거나 AuthenticationException 일 경우 인증을 시작한다

 -> 인증되지 않았으니 있던 SecurityContextHolder 를 날린다 -> 인증이 만약 성공된다면 다시 사용할 수 있도록 HttpServletRequest가 저장된다. 

 

AuthenticationEntryPoint 는 클라이언트의 자격 증명을 요청한다. << 이때 로그인 페이지를 정해주면 그 페이지로 리디렉션해주거나 WW-Authenticate header.를 보내준다.

 

3. 만약 그래도 AccessDeniedException 일 경우에는 접근이 거부됐다. 거부에 대한 액세스 처리를 위해 AccessDeniedHandler가 호출된다

 

 

 If the application does not throw an AccessDeniedException or an AuthenticationException, then ExceptionTranslationFilter does not do anything.

 

 

ExceptionTranslationFilter pseudocode

try {
	filterChain.doFilter(request, response);
} catch (AccessDeniedException | AuthenticationException ex) {
	if (!authenticated || ex instanceof AuthenticationException) {
		startAuthentication();
	} else {
		accessDenied();
	}
}

1. filterChain.doFilter(request, response) 호출 하여 애플리케이션 호출 인증됐으면 넘어가고, 아니면 catch 에서 처리 되는 것

2. 인증 요청 startAuthentication()

3. 거부됨 accessDenied()

 

 

Saving Requests Between Authentication

ExceptionTranslationFilter 코드를 보면 authenticated가 있다

이처럼 요청에 인증이 없고 인증이 필요한 리소스에 대한 요청이면 인증 성공 한 후에는 (authenticated 가 true가 됐을 때) 이 요청을 저장해야한다. 이는 HttpServletRequest 의 RequestCache 를 이용하여 수행 된다

 

RequestCache

사용자가 성공적으로 인증되면 RequestCache가 재요청 시에 사용된다

RequestCacheAwareFilter는 RequestCache를 사용하여 HttpServletRequest를 저장한다

 

기본적으로 HttpSessionRequestCache가 사용된다

 

 

 

RequestCache Only Checks for Saved Requests if continue Parameter Present

@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
	HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
	requestCache.setMatchingRequestParameterName("continue");
	http
		// ...
		.requestCache((cache) -> cache
			.requestCache(requestCache)
		);
	return http.build();
}

 

 

RequestCacheAwareFilter

The RequestCacheAwareFilter uses the RequestCache to save the HttpServletRequest.

728x90