๐ป Spring Security docs ๊ฒ์๊ธ ๋ชฉ์ฐจ
1. [Spring Security] docs : Getting Started
[Spring Security] docs : Getting Started
Spring Security๋ ์ธ์ฆ, ๊ถํ๋ถ์ฌ ๋ฐ ์ผ๋ฐ์ ์ธ ๊ณต๊ฒฉ์ ๋ํ ๋ณดํธ๋ฅผ ์ ๊ณตํ๋ ํ๋ ์์ํฌ์ด๋ค. ๊ฐ๋ฐ์๊ฐ ๋ณด์ ์ค์ ์ ์ถ๊ฐ์ ์ผ๋ก ์ ๊ฒฝ์ฐ์ง ์๋๋ผ๋ ์์ ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น ๋ฅด๊ฒ ๊ตฌ์ถํ ์ ์๋
kiritoni.tistory.com
2. [Spring Security] docs : Architecture (1) - Filter
[Spring Security] docs : Architecture (1) - Filter
Spring Security docs Hello Spring Security :: Spring SecurityRunning Spring Boot Application $ ./mvnw spring-boot:run ... INFO 23689 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration : Using generated security password: 8e557245-73e2-4286-969a
kiritoni.tistory.com
3. [Spring Security] docs: Architecture (2) - DelegatingFilterProxy
[Spring Security] docs: Architecture (2) - DelegatingFilterProxy
Spring Security docs Hello Spring Security :: Spring SecurityRunning Spring Boot Application $ ./mvnw spring-boot:run ... INFO 23689 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration : Using generated security password: 8e557245-73e2-4286-969a
kiritoni.tistory.com
4. [Spring Security] docs: Architecture (3) - FilterChainProxy & SecurityFilterChain
[Spring Security] docs: Architecture (3) - FilterChainProxy & SecurityFilterChain
2024.08.29 - [Spring Boot] - [Spring Security] docs: Architecture (2) - DelegatingFilterProxy [Spring Security] docs: Architecture (2) - DelegatingFilterProxySpring Security docs Hello Spring Security :: Spring SecurityRunning Spring Boot Application $ .
kiritoni.tistory.com
[Spring Security] docs : Architecture(4) : FilterChain์ ์ญํ ๊ณผ ์์, ์ปค์คํ ํํฐ
๐ป Spring Security docs ๊ฒ์๊ธ ๋ชฉ์ฐจ ๋๋ณด๊ธฐ1. [Spring Security] docs : Getting Started [Spring Security] docs : Getting StartedSpring Security๋ ์ธ์ฆ, ๊ถํ๋ถ์ฌ ๋ฐ ์ผ๋ฐ์ ์ธ ๊ณต๊ฒฉ์ ๋ํ ๋ณดํธ๋ฅผ ์ ๊ณตํ๋ ํ๋ ์์ํฌ
kiritoni.tistory.com
๐ฑ Spring Security docs ๋ฐ๋ก๊ฐ๊ธฐ
Architecture :: Spring Security
The Security Filters are inserted into the FilterChainProxy with the SecurityFilterChain API. Those filters can be used for a number of different purposes, like authentication, authorization, exploit protection, and more. The filters are executed in a spec
docs.spring.io
ExceptionTranslationFilter
`ExceptionTranslationFilter`๋ ๋ณด์ ํํฐ๋ค ์คํ๋๋ก, FilterChainProxy์ ๋ค์ด์๋ค. `ExceptionTranslationFilter`๋ `AccessDeniedException` ๊ณผ `AuthenticationException` ์ HTTP ์๋ต์ผ๋ก ๋ณํ์ํฌ ์ ์๋ค.
1. `ExceptionTranslationFilter`๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋จธ์ง๋ฅผ ํธ์ถํ๊ธฐ ์ํด `FilterChain.doFilter(request, response)`๋ฅผ ํธ์ถํ๋ค.
2. ๋ง์ฝ ์ ์ ๊ฐ ์ธ์ฆ๋์ง ์์๊ฑฐ๋, `AuthenticationException`์ ํด๋นํ๋ฉด ์ธ์ฆ์ ์์ํ๋ค.
- `SecurityContextHolder`๊ฐ ์ญ์ ๋๋ค.
- `HttpServletRequest`๊ฐ ์ ์ฅ๋๋๋ฐ, ์ธ์ฆ์ด ์ฑ๊ณตํ๋ฉด ์๋์ ์์ฒญ์ ์ฌ์คํํ๋ ๋ฐ์ ์ฐ์ธ๋ค.
- `AuthenticationEntryPoint`๋ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ credential์ ์์ฒญํ๋ ๋ฐ ์ฌ์ฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ก๊ทธ์ธ ํ์ด์ง๋ `WWW-Authenticate` ํค๋๋ก ๋ฆฌ๋ค์ด๋ ํธ ์ํฌ ์ ์๋ค.
3. ๋ฐ๋ฉด์ `AccessDeniedException`์ธ ๊ฒฝ์ฐ์๋, ์ ๊ทผ์ด ๊ฑฐ๋ถ๋๊ณ , ์ด๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด `AccessDeniedHandler`๊ฐ ํธ์ถ๋๋ค.
โ ๋ง์ฝ ์ ํ๋ฆฌ์ผ์ด์ ์ด `AccessDeniedException`์ด๋ `AuthenticationException`์ ๋์ง์ง ์์ผ๋ฉด `ExceptionTranslationFilter`๊ฐ ์๋ฌด๊ฒ๋ ํ์ง ์๋๋ค.
`ExceptionTranslationFilter` ์๋ ์ฝ๋
try {
filterChain.doFilter(request, response); // 1
} catch (AccessDeniedException | AuthenticationException ex) {
if (!authenticated || ex instanceof AuthenticationException) {
startAuthentication(); // 2
} else {
accessDenied(); // 3
}
}
1. `FilterChain.doFilter(request, response)`๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋๋จธ์ง ์ ํ๋ฆฌ์ผ์ด์ ์ ํธ์ถํ๋ ๊ฒ๊ณผ ๋์ผํ ์ญํ ์ ํ๋ค. ์ฆ, ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ (`FilterSecurityInterceptor`์ด๋ method security)์ด `AuthenticationException`์ด๋ `AccessDeniedException`์ ๋์ง๋ฉด ์ฌ๊ธฐ์ ์กํ๊ณ ์ฒ๋ฆฌ๋๋ค.
2. ์ ์ ๊ฐ ์ธ์ฆ๋์ง ์์๊ฑฐ๋ `AuthenticationException`์ ํด๋นํ๋ฉด ์ธ์ฆ์ด ์์๋๋ค.
3. ์ ๊ทผ ๊ฑฐ๋ถ
์ธ์ฆ ์ฌ์ด์ ์์ฒญ ์ ์ฅํ๊ธฐ
์์ฒญ์ ์ธ์ฆ์ด ์๊ณ ์ธ์ฆ์ด ํ์ํ ๋ฆฌ์์ค์ ๋ํ ์์ฒญ์ธ ๊ฒฝ์ฐ, ์ธ์ฆ์ด ์ฑ๊ณตํ ํ ์ธ์ฆ ๋ฆฌ์์ค๋ฅผ ์ฌ์์ฒญํ๊ธฐ ์ํด ์์ฒญ์ ์ ์ฅํด๋์ด์ผ ํ๋ค.
์ด๋ฅผ ์ํด Spring Security์์๋ `RequestCache` ๊ตฌํ์ ํตํด `HttpServletRequest`๋ฅผ ์ ์ฅํ ์ ์๋ค.
RequestCache
`HttpServletRequest`๋ `RequestCache`์ ์ ์ฅ๋๋ค.`RequestCacheAwareFilter`์ `ExceptionTranslationFilter`๋ ๋ชจ๋ `RequestCache`๋ฅผ ์ฌ์ฉํ์ง๋ง, ์ฌ์ฉํ๋ ์์ ๊ณผ ๋ชฉ์ ์ด ๋ค๋ฅด๋ค.
`RequestCacheAwareFilter`: ์ ์ ๊ฐ ์ธ์ฆ์ ์ฑ๊ณตํ ๋ค์ RequestCache์ ์ ์ฅ๋ ์๋ณธ ์์ฒญ์ด ์๋์ง ํ์ธํ๊ณ , ๋ง์ฝ ์๋ค๋ฉด ๊ทธ ์์ฒญ์ ์๋ ์์ฒญ์ ๋ณต์ํ์ฌ ์ธ์ฆ ์ฑ๊ณต ํ์ ๊ฒฝ๋ก๋ก ๋ฆฌ๋ค์ด๋ ํธํ๋ค. ์ฆ, ์ด๋ฏธ ์ ์ฅ๋ ์์ฒญ์ ๊ฒ์ํ์ฌ ์ฒ๋ฆฌํ๋ ํํฐ์ด๋ค.
`ExceptionTranslationFilter`: ์ธ์ฆ์ด ํ์ํ ์์ฒญ์ ์ ๋ฆฌํ๋ ๊ณผ์ ์์ ์ธ์ฆ ์์ธ (`AuthenticationException`)๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ, ์ ์ ๊ฐ ๋ก๊ทธ์ธ ์๋ํฌ์ธํธ๋ก ๋ฆฌ๋ค์ด๋ ํธ๋๊ธฐ ์ ์ `HttpServletRequest`์ `RequestCache`์ ์ ์ฅํ๋ค.
โ ๊ธฐ๋ณธ๊ฐ์ผ๋ก `HttpSessionRequestCache`๋ฅผ ์ฌ์ฉํ์ฌ `HttpSession`์ ์์ฒญ์ ์ ์ฅํ๋ค.
์ปค์คํฐ๋ง์ด์ง๋ RequestCache ๊ตฌํ
์๋์ ์ฝ๋๋ `HttpSessionRequestCache`๊ฐ `continue` ๋ผ๋ ํน์ ํ๋ผ๋ฏธํฐ๊ฐ ์์ ๋๋ง ์์ฒญ์ ์ ์ฅํ๋๋ก ์ปค์คํฐ๋ง์ด์งํ ๊ฒ์ด๋ค.
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
requestCache.setMatchingRequestParameterName("continue");
http
// ...
.requestCache((cache) -> cache
.requestCache(requestCache)
);
return http.build();
}
`NullRequestCache` ๊ตฌํ์ ํตํด ์์ฒญ์ด ์ ์ฅ๋๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ
์ธ์ ์ ์ ์ ์ ์ธ์ฆ๋์ง ์์ ์์ฒญ์ ์ ์ฅํ๊ณ ์ถ์ง ์์ ์ ์๋ค. ํด๋น ์คํ ๋ฆฌ์ง๋ฅผ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ๋ก ์คํ๋ก๋ํ๊ฑฐ๋, ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ ์ ์๋ค. ๋๋ ๋ก๊ทธ์ธ ์ ์ ๋ฐฉ๋ฌธํ๋ ค๊ณ ํ๋ ํ์ด์ง ๋์ , ํญ์ ํน์ ํ์ด์ง(ex. ํ ํ์ด์ง)๋ก ์ฌ์ฉ์๋ฅผ ๋ฆฌ๋๋ ์ ํ๊ณ ์ถ๋ค๋ฉด ์์ฒญ์ ์ ์ฅํด๋์ง ์๊ณ ์ถ์ ์ ์๋ค. ๊ทธ๋ด ๋์๋ `NullRequestCache`๋ฅผ ๊ตฌํํ๋ฉด ๋๋ค.
@Bean
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
RequestCache nullRequestCache = new NullRequestCache();
http
// ...
.requestCache((cache) -> cache
.requestCache(nullRequestCache)
);
return http.build();
}
์ ๋ฆฌํ์๋ฉด, `NullRequestCache`๋ ์์ฒญ์ ์บ์ฑํ์ง ์๋๋ค. ๋ฐ๋ผ์ ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ๋ ํ, ์๋ ์์ฒญ์ ๋ค์ ์คํํ ํ์๊ฐ ์๋ ์ํฉ์ ์ ํฉํ๋ค.
๋ก๊น
Spring Security๋ ๋ณด์ ์ด๋ฒคํธ์ ๋ํ ์ข ํฉ์ ์ธ ๋ก๊ทธ๋ฅผ DEBUG์ TRACE ๋ ๋ฒจ์์ ์ ๊ณตํ๋ค. 401์ด๋ 403 ์๋ฌ๊ฐ ๋ฌ๋ค๋ฉด, ํ์ฌ ์ด๋ค ์ํฉ์ด ๋ฒ์ด์ก๋์ง์ ๋ํ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์ฐพ์ ์ ์์ ํ๋ฅ ์ด ๋๋ค.
csrf ๋ณดํธ๊ฐ ๋ ๋ฆฌ์์ค๋ฅผ csrf ํ ํฐ์ด ์์ด POST ์์ฒญ์ ๋ณด๋ด๋ฉด, ๋ก๊ทธ๊ฐ ์์ด๋ ์ ์ ๊ฐ ์๋ฌด ์ค๋ช ๋ ์์ด 403์๋ฌ๋ฅผ ๋ง์ฃผ์น ๊ฒ์ด๋ค. ํ์ง๋ง, Spring Security์ ๋ก๊น ์ ํ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฉ์์ง๋ฅผ ๋ณผ ์ ์๋ค.
2023-06-14T09:44:25.797-03:00 DEBUG 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Securing POST /hello
2023-06-14T09:44:25.797-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking DisableEncodeUrlFilter (1/15)
2023-06-14T09:44:25.798-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking WebAsyncManagerIntegrationFilter (2/15)
2023-06-14T09:44:25.800-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderFilter (3/15)
2023-06-14T09:44:25.801-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking HeaderWriterFilter (4/15)
2023-06-14T09:44:25.802-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking CsrfFilter (5/15)
2023-06-14T09:44:25.814-03:00 DEBUG 76975 --- [nio-8080-exec-1] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://localhost:8080/hello
2023-06-14T09:44:25.814-03:00 DEBUG 76975 --- [nio-8080-exec-1] o.s.s.w.access.AccessDeniedHandlerImpl : Responding with 403 status code
2023-06-14T09:44:25.814-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match request to [Is Secure]
CSRF ํ ํฐ์ด missing ์ํ์ด๊ณ , ๊ทธ๋์ ์์ฒญ์ด denied๋์์์ ์ ์ ์๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ค์ ํ ์ ์๋ค.
application.properties
logging.level.org.springframework.security=TRACE
application.yml
logging:
level:
org.springframework.security: DEBUG
org.springframework.security.web: TRACE
logback.xml
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- ... -->
</appender>
<!-- ... -->
<logger name="org.springframework.security" level="trace" additivity="false">
<appender-ref ref="Console" />
</logger>
</configuration>
๐ป ๋ก๊น ํ๋ ์์ํฌ Logback
`logback.xml`์ Logback ์ด๋ผ๋ ๋ก๊น ํ๋ ์์ํฌ์ ์ค์ ํ์ผ์ด๋ค.
1. ๋ก๊น
์ถ๋ ฅ ๋์ (Appenders) ์ค์
`Appender`๋ ๋ก๊น ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ ๋์์ด๋ค. ์์ ์ฝ๋์์๋ `STDOUT์ด`๋ผ๋ ์ด๋ฆ์ ์ฝ์์ด ์ ์๋์ด ์๋ค. ์ด ์ฝ์์ `ConsoleAppender`ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ํ์ค ์ถ๋ ฅ์ ๊ธฐ๋กํ๋ค.
2. ๋ก๊น
๋ ๋ฒจ ๋ฐ ๋ก๊ฑฐ ์ ์
`logger`๋ ํน์ ํจํค์ง๋ ํด๋์ค์ ๋ก๊ทธ ์ถ๋ ฅ์ ๊ด๋ฆฌํ๋ค. `name` ์์ฑ์ ๋ก๊ฑฐ์ ์ด๋ฆ์ ์ง์ ํ๋ฉฐ, ๋ณดํต ํน์ ํจํค์ง๋ ํด๋์ค ์ด๋ฆ์ ์ฌ์ฉํ๋ค.
`level` ์์ฑ์ ๋ก๊น
๋ ๋ฒจ์ ์ ์ํ๋ค. `trace`, `debug`, `info`, `warn`, `error` ๋ฑ์ด ์๋ค. ์ ์ฝ๋์์๋ `trace` ๋ ๋ฒจ๋ก ์ค์ ๋์๊ณ , `trace`๋ ๊ฐ์ฅ ์์ธํ ๋ก๊ทธ๋ ๋ฒจ์ด๋ค. ์ถ๊ฐ์ ์ผ๋ก `additivity="false"`๋ ์ด ๋ก๊ฑฐ๊ฐ ์์ ๋ก๊ฑฐ์ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์ ๋ฌํ์ง ์๋๋ก ํ์ฌ, ๋ถํ์ํ ์ค๋ณต ๋ก๊ทธ๋ฅผ ๋ฐฉ์งํด์ค๋ค.
3. ๋ก๊น
๋ฉ์์ง์ ํฌ๋งท๊ณผ ํํฐ๋ง
`logback.xml`์ ์ฌ์ฉํ๋ฉด ๊ฐ ๋ก๊ทธ ๋ฉ์์ง์ ํฌ๋งท์ ์ ์ํ๊ฑฐ๋, ํน์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ํํฐ๋งํ ์ ์๋ค.