Spring Security 설정 (작성중)

jomminii_before·2022년 6월 24일
0

spring

목록 보기
3/4
post-custom-banner

build.gradle 설정


dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-security'
    testImplementation 'org.springframework.security:spring-security-test'

}

토리맘의 한글라이즈 프로젝트 - Spring Security doc 5.3.2 기준 번역
Spring Security doc

망나니개발자 - [Spring] 필터(Filter) vs 인터셉터(Interceptor) 차이 및 용도 - (1)
출처: https://mangkyu.tistory.com/173 [MangKyu's Diary:티스토리]

[Spring Security] Filter란?

코딩스타트 - Spring boot - Spring Security(스프링 시큐리티) 란? 완전 해결!

SecurityConfig 설정

기존에는 WebSecurityConfigurerAdapter를 상속받은 Config class 를 만들어 security 설정을 했으나 Spring Security 5.7.0-M2 부터 deprecated 되어버렸다.
(하지만 아직 공식 doc 에서도 기존방식을 쓰라고 가이드 중_22.06.22 기준)

하지만 Spring Blog - spring security without the websecurityconfigureradapter 라는 글에 새로운 구현 방법이 설명되어 있어서 참고해 작성해보려 한다.

WebSecurity vs HttpSecurity

WebSecurity는 패턴에 해당하는 리소스에 아예 Spring Security를 적용하지 않도록 설정한다. 그렇기에 자유롭게 access가 가능해진다.

This will omit the request pattern from the security filter chain entirely. Note that anything matching this path will then have no authentication or authorization services applied and will be freely accessible.

HttpSecurityWebSecurity에서 제외된 리소스 외의 부분에 Spring Securiy를 설정할 수 있게 해준다. authorizeRequests를 통해 리소스의 인증 부분을 ignore 할 수 있다고 해도 그외 다른 security 기능들에 대해서는 영향을 받는다.(secure header, CSRF protection 등)

stackoverflow - Spring Security Configuration - HttpSecurity vs WebSecurity

WebSecurity

WebSecurityCustomizer를 통해 Spring Security를 적용하지 않을 리소스를 설정한다. WebSecurityCustomizer가 함수형 인터페이스라 아래와 같이 작성하면 로직이 작동한다.

public class SecurityConfig {

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> {
            web.ignoring()
                .antMatchers(
                    "/api-document/**",
                    "/swagger-ui/**"
                    );
        };
    }
}

HttpSecurity

CSRF(Cross-Site Request Forgery)

사이트 간 요청 위조라는 공격 방식으로 사용자가 의도하지 않았지만 공격자의 의도에 따라 자신도 모르게 서버를 공격하게 되는걸 CSRF 라고 한다.

쿠키를 기반으로 한 인증 방식일 때 사용되는 공격방식인데, Spring Security에서는 기본 설정으로 이 방식이 적용되어 있다. 이 방식이 적용되어 있으면 CSRF 토큰 방식을 사용해서 인증을 진행해야하는데, REST API 방식을 사용할 때는 쿠키를 사용해서 인증하는 방식을 잘 사용하지 않기에 설정을 꺼두어도 무방하다.

아래 참고 글들을 보면 쿠키를 통한 인증방식을 사용하지 않는다면 CSRF
를 방어하지 않아도 좋다고 한다. 이번 설정에서도 쿠키는 사용하지 않기에 disable 처리 해두었다.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable();
        return http.build();
    }
}

Should I use CSRF protection on Rest API endpoints?
CSRF(Cross-Site Request Forgery) 공격과 방어

CORS

Spring Security는 기본적으로 CORS 를 허용하지 않도록 설정되어있기 때문에 허용하고 싶다면 추가 설정을 해야 한다.

setAllowCredentials : cross origin 으로부터 인증을 위한 쿠키 정보를 받을지 여부.
setAllowedOrigins : 허용할 origin 정보.
setAllowedMethods : 허용할 http methods.

addAllowedHeader, Method, Origin : 위의 set 들은 리스트로 받았다면, add는 개별 지정(* 등)

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
        	.cors().configurationSource(corsConfigurationSource());
        return http.build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowCredentials(false); // 쿠키를 받을건지
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST"));

        configuration.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;

    }
}

Spring doc - CORS

exceptionHandling

Security filter에서 발생하는 인증, 인가 관련 에러 처리를 해준다. 필터에서 발생한 에러기에 dispatcher servlet 까지 닿지 못하고, 내부에 만들어 놓은 custom exception 을 사용할 수 없다. 그렇기에 원하는 에러 처리를 하려면 추가 설정을 해줘야한다.

각각 AuthenticationExceptionAccessDeniedException 발생시 실행된다.
exceptionHandling().authenticationEntryPoint(설정)으로 authenticationEntryPoint 설정. ExceptionTranslationFilter 필터에서 이 설정을 사용하는데 AuthenticationException 이 발생하면 authenticationEntryPoint를 실행시킨다. accessDeniedHandler도 동일하게 작동한다.

If an AuthenticationException is detected, the filter will launch the authenticationEntryPoint. This allows common handling of authentication failures originating from any subclass of AbstractSecurityInterceptor.
If an AccessDeniedException is detected, the filter will determine whether or not the user is an anonymous user. If they are an anonymous user, the authenticationEntryPoint will be launched. If they are not an anonymous user, the filter will delegate to the AccessDeniedHandler. By default the filter will use AccessDeniedHandlerImpl.
Spring doc - Class ExceptionTranslationFilter

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .exceptionHandling()
            .authenticationEntryPoint() // 인증 에러 핸들링
            .accessDeniedHandler() // 인가 에러 핸들링
        ;
        return http.build();
    }

Spring doc - AuthenticationEntryPoint
Spring doc - AccessDeniedHandler

hoons.log - 스프링시큐리티 JWT 예외처리
Spring Security JWT 토큰 검증 시 Exception 예외 처리

sessionManagement

세션을 어떻게 관리할지 설정한다.
sessionCreationPolicy : 어떤 생성 전략을 가져갈지 설정한다.

	/**
	 * Always create an {@link HttpSession}
	 */
	ALWAYS,

	/**
	 * Spring Security will never create an {@link HttpSession}, but will use the
	 * {@link HttpSession} if it already exists
	 */
	NEVER,

	/**
	 * Spring Security will only create an {@link HttpSession} if required
	 */
	IF_REQUIRED,

	/**
	 * Spring Security will never create an {@link HttpSession} and it will never use it
	 * to obtain the {@link SecurityContext}
	 */
	STATELESS (JWT 같은 토큰 방식을 쓸때 사용)
    // SessionCreationPolicy.STATELESS 설정이 스프링 시큐리티가  무조건 세션을 생성하지 않는다는 의미보다는 
    // 인증 처리 관점에서 세션을 생성하지 않음과 동시에 세션을 이용한  방식으로 인증을 처리하지 않겠다는 의미로 해석할 수 있다는 점이고
    // 인증메커니즘이 아닌 다른 특정한 곳에서 세션과 관련된 처리를 해야 하는 경우나 
    // 스프링이 아닌 다른 어플리케이션에서 세션을 사용하는 곳이 있다면 세션이 생성 될 수도 있다는 점입니다. (인프런 답변 참고)

STATELESS 관련 인프런 답변

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        ;
        return http.build();
    }

authorizeRequests

path matching 기반으로 인증, 인가가 필요한 부분을 설정한다. antMatchers를 통해 적용할 경로를 설정하고, hasRole, permitAll, authenticated 등을 통해 누가 접근할 수 있는지 설정할 수 있다.

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/member/**").permitAll() // token 설정 전까지 오픈
            .antMatchers("/api-document/**").permitAll()
            .antMatchers("/swagger-ui/**").permitAll()
            .anyRequest().authenticated(); // 그 외 모든 요청에 대해 인증 필요
        return http.build();
    }
profile
https://velog.io/@jomminii 로 이동했습니다.
post-custom-banner

0개의 댓글