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.

Disable CSRF Protection in Spring Boot

@EnableWebSecurity
class SecurityConfig {
    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        http.csrf().disable()

        return http.build()
    }
}

cors