주뇽's 저장소

[Spring Security] 스프링 시큐리티 커스터마이징 Spring Security Filter Chain 본문

웹개발/SpringBoot

[Spring Security] 스프링 시큐리티 커스터마이징 Spring Security Filter Chain

뎁쭌 2024. 1. 23. 19:36
728x90
반응형

스프링 시큐리티 필터 체인 설정 

스프링 시큐리티(Spring Security)는 자바(Java) 기반의 애플리케이션을 위한 강력한 인증 및 접근 제어 프레임워크다. 스프링 프레임워크(Spring Framework)의 일부로, 웹 애플리케이션과 메소드 수준의 보안을 제공한다. 이는 애플리케이션의 보안을 강화하기 위해 맞춤화하고 확장할 수 있는 다양한 기능들을 포함하고 있다.

주요 특징

  1. 인증(Authentication): 사용자가 누구인지 확인하는 과정이다. 스프링 시큐리티는 다양한 인증 메커니즘을 지원하며, 이를 통해 사용자 이름과 비밀번호, 토큰 기반 인증, LDAP, OAuth 등 다양한 방식으로 인증을 수행할 수 있다.
  2. 권한 부여(Authorization): 인증된 사용자가 특정 자원에 접근하거나 특정 작업을 수행할 수 있는 권한을 가지고 있는지 결정하는 과정이다. 역할 기반 접근 제어(RBAC)를 포함해 다양한 접근 제어 모델을 지원한다.
  3. 세션 관리(Session Management): 사용자 세션을 관리하며, 동시 세션, 세션 고정 보호, 세션 만료 등의 기능을 제공한다.
  4. CSRF(Cross-Site Request Forgery) 보호: 웹 애플리케이션을 CSRF 공격으로부터 보호한다. 이는 사용자가 의도하지 않은 작업을 수행하도록 만드는 공격을 막아준다.
  5. CORS(Cross-Origin Resource Sharing): 다른 도메인에서의 자원 접근을 안전하게 허용하는 방법을 제공한다.
  6. LDAP(Lightweight Directory Access Protocol) 통합: 디렉토리 서비스와의 통합을 지원하여 사용자 인증 및 권한 부여에 LDAP 서버를 사용할 수 있다.
  7. OAuth 및 OpenID Connect 지원: 외부 서비스를 이용한 인증 방식을 지원하여, 소셜 로그인 같은 기능을 구현할 수 있다.

사용 방법

스프링 시큐리티는 spring-boot-starter-security 의존성을 프로젝트에 추가함으로써 쉽게 통합할 수 있다. 기본 설정은 많은 보안 기능을 자동으로 제공하지만, SecurityFilterChain을 정의해줌으로 세부적으로 커스텀 할 수있다.

 

아래는 기본적인 Filter를 커스텀한 것이다. 모든 설정은 람다식으로 해야한다.

package com.spring_react_board_study.spring_react_board.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SpringConfig {

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
        http
                .authorizeHttpRequests((auth) -> auth 
                    .requestMatchers("/", "/login", "/signup").permitAll()
                    .requestMatchers("/admin").hasRole("ADMIN")
                    .requestMatchers("/api/v1/**").hasAnyRole("USER", "ADMIN")
                    .anyRequest().authenticated()
                );
        http.httpBasic(Customizer.withDefaults());
        http.sessionManagement(
                session -> session.sessionCreationPolicy
                        (SessionCreationPolicy.STATELESS));
        http.csrf(AbstractHttpConfigurer::disable);
        http.headers().frameOptions().sameOrigin();
        return http.build();
    }
}

 

0. 기본 Bean 설정

  • @Configuration: 이 클래스가 스프링의 설정 클래스임을 나타낸다
  • @EnableWebSecurity: 이 어노테이션은 웹 보안을 활성화한다.

1. 보안 필터 체인

  • SecurityFilterChain: HTTP 요청에 대한 보안 처리를 정의한다. HttpSecurity 객체를 사용하여 HTTP 보안 구성을 커스터마이징한다.

1-1 authorizeHttpRequests(): HTTP 요청에 대한 보안 규칙을 정의한다. 

 

http
                .authorizeHttpRequests((auth) -> auth 
                    .requestMatchers("/", "/login", "/signup").permitAll()
                    .requestMatchers("/admin").hasRole("ADMIN")
                    .requestMatchers("/api/v1/**").hasAnyRole("USER", "ADMIN")
                    .anyRequest().authenticated()
                );
  • .requestMatchers(...).permitAll(): 특정 경로들에 대해 모든 사용자의 접근을 허용한다.
    • 홈페이지, 로그인, 회원가입 페이지에 대해서는 인증없이 접근이 가능해야 한다.
  • .requestMatchers("/admin").hasRole("ADMIN"): "/admin" 경로에는 "ADMIN" 역할을 가진 사용자만 접근할 수 있다.
  • .requestMatchers("/api/v1/**").hasAnyRole("USER", "ADMIN"): "/api/v1/**" 경로에는 "USER" 또는 "ADMIN" 역할을 가진 사용자가 접근할 수 있다.
  • anyRequest().authenticated() : 이외 모든 접근에 대해서는 인증을 진행한다.
  • 위 필터들은 순차적으로 실행되므로 순서에 유의 하도록 하자.!

1-2 httpBasic(): 기본 HTTP 인증을 사용한다.

http.httpBasic(Customizer.withDefaults());
  • JWT로 바꿀 경우 필요없을듯

 

1-3 sessionManagement(): 세션 관리 설정을 정의한다. 여기서는 SessionCreationPolicy.STATELESS를 사용하여 세션을 생성하지 않는다.

http.sessionManagement(
                session -> session.sessionCreationPolicy
                        (SessionCreationPolicy.STATELESS));
  • JWT로 RestFull하게 인증을 진행할 경우 세션을 생성하지 않아도 된다.(View를 React나 다른 프레임워크를 사용할 경우)

1-4 csrf().disable(): CSRF(Cross-Site Request Forgery) 보호 기능을 비활성화한다.

http.csrf(AbstractHttpConfigurer::disable);
  • CSRF : 세션이 남아있는 경우에 대한 PUT, POST, DELETE 요청에 대한 보호
  • Stateless한 RestAPI를 사용하는 경우 CSRF를 비활성화 해도 보안상 큰 문제가 없다.

1-5 headers().frameOptions().sameOrigin(): 클릭재킹 방지를 위한 설정이다. 동일 출처의 프레임에서만 응답을 허용한다.

http.headers().frameOptions().sameOrigin();
  • h2 데이터베이스를 사용하는경우 프레임이 안보이는 문제를 해결하기 위한 코드이며 h2-consle을 사용하지 않는다면 필요 없는 코드이다.

 

참고

 RESTful API는 상태가 없는(stateless) 특성을 가진다. 즉, 각 요청은 독립적이며 이전 상태를 기억하지 않는다. JWT를 사용한 인증은 이 원칙을 따른다. 클라이언트는 각 요청마다 JWT를 전송하며, 서버는 세션을 유지할 필요 없이 토큰을 검증하여 요청을 처리한다.