Spring Security
spring security
Security Core
SecurityContextHolder
- Default Strategy: ThreadLocal
- SecurityContext 를 저장
- MODE_THREADLOCAL: 스레드당 SecurityContext 객체 할당
- MODE_INHERITABLETHREADLOCAL: 메인 스레드와 자식 스레드에 관하여 동일한 SecurityContext 유지
- MODE_GLOBAL: 응용 프로그램에서 단 하나의 SecurityContext 를 저장
- SecurityContextHolder().clearContext(): SecurityContext 기존 정보 초기화
SecurityContext
- Authentication 객체가 저장되는 보관소
- ThreadLocal 에 저장되어 아무 곳에서나 참조 가능
- 인증이 완료되면 HttpSession 에 저장되어 애플리케이션 전바에 걸쳐 전역적인 참조 가능
ThreadLocalSecurityContextHolderStrategy
final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<>();
@Override
public void clearContext() {
contextHolder.remove();
}
@Override
public SecurityContext getContext() {
SecurityContext ctx = contextHolder.get();
if (ctx == null) {
ctx = createEmptyContext();
contextHolder.set(ctx);
}
return ctx;
}
@Override
public void setContext(SecurityContext context) {
Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
contextHolder.set(context);
}
@Override
public SecurityContext createEmptyContext() {
return new SecurityContextImpl();
}
}
Config
WebSecurityConfigurerAdapter
Spring Security without the WebSecurityConfigurerAdapter. In Spring Security 5.7.0-M2 we deprecated the WebSecurityConfigurerAdapter,
- AS-IS
@EnableWebSecurity
class WebSecurity: WebSecurityConfigurerAdapter() {
override fun configure(web: WebSecurity) {
}
override fun configure(http: HttpSecurity) {
}
}
- TO-BE
@EnableWebSecurity
class SecurityConfig {
private val log = LoggerFactory.getLogger(this::class.java)
@Bean
fun webSecurityCustomizer(): WebSecurityCustomizer {
return WebSecurityCustomizer { web: WebSecurity ->
web.debug(false)
.ignoring()
.antMatchers("/css/**", "/js/**", "/img/**", "/lib/**", "/favicon.ico")
}
}
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http.cors().and()
.httpBasic().disable()
.anyRequest().authenticated()
return http.build()
}
}
csrf
Spring Security enables CSRF protection by default since version 4
Does REST API Require CSRF Protection?
Let's take a typical example: a Spring REST API application and a Javascript client. The client uses a secure token as credentials (such as JSESSIONID or JWT), which the REST API issues after a user successfully signs in.
CSRF vulnerability depends on how the client stores and sends these credentials to the API
CSRF and Stateless Browser Applications
- Cookie
- JWT 를 사용하는 stateless 한 애플리케이션의 경우에도 토큰을 쿠키에 저장하여 클라이언트로부터 전달 받는다면 CSRF 공격에 취약해질 수 있다.
- Browser Storage
- JWT Local Storage(Browser Storage) 에 저장한다면 Local Storage 는 SOP(same origin policy)를 갖기 대문에 CSRF 공격을 막을 수 있다.
- This is a prevalent way to use, for example, JWT: it's easy to implement and prevents attackers from using CSRF attacks. Indeed, unlike cookies, the browser storage variables are not sent automatically to the server.
- However, this implementation is vulnerable to XSS attacks.
- A malicious JavaScript code can access the browser storage and send the token along with the request. In this case, we must protect our application.
- JWT Local Storage(Browser Storage) 에 저장한다면 Local Storage 는 SOP(same origin policy)를 갖기 대문에 CSRF 공격을 막을 수 있다.
Disable CSRF Protection in Spring Boot
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http.csrf().disable()
return http.build()
}
}