Spring Security

leedong617·2024년 10월 8일
post-thumbnail

Spring Security는 스프링 프레임워크(Spring Framework) 기반 애플리케이션에서 보안(인증 및 권한 부여) 기능을 제공하는 강력한 보안 프레임워크임. 이 프레임워크는 애플리케이션에서 인증(Authentication), 인가(Authorization, 권한 부여), 세션 관리, 암호화 등을 쉽게 구현할 수 있도록 도와줌. 또한, 웹 애플리케이션뿐만 아니라 메소드 기반 보안, REST API 보안도 함께 지원함.

Spring Security는 매우 유연하고 확장 가능하여, 기본적인 보안 기능뿐만 아니라 커스터마이징이 필요할 때도 효율적으로 사용할 수 있음.

Spring Security의 주요 개념

인증(Authentication)

인증(Authentication)은 사용자가 누구인지 확인하는 과정임. 보통 사용자명과 비밀번호를 통해 사용자를 인증하고, 인증이 성공하면 해당 사용자에 대한 정보를 세션에 저장하거나 토큰을 생성함.

인증 프로세스는 사용자가 시스템에 접근하려고 할 때 발생하며, 로그인 절차를 통해 사용자가 누구인지 확인하는 절차임.
성공적인 인증이 이루어지면, 인증 토큰이나 세션을 통해 사용자의 상태를 유지함.

인가(Authorization, 권한 부여)

인가(Authorization)는 인증된 사용자가 특정 자원에 접근할 권한이 있는지를 확인하는 과정임. 권한 부여는 사용자에게 할당된 역할(Role)이나 권한(Authority)에 따라 결정됨.

예를 들어, 관리자(Admin) 역할을 가진 사용자는 모든 자원에 접근할 수 있지만, 일반 사용자(User)는 특정 자원만 접근할 수 있도록 권한이 제한됨.

보안 컨텍스트(Security Context)

Security Context는 인증된 사용자의 세부 정보를 포함하고 있는 저장소임. 인증된 사용자의 세션 또는 토큰에 저장되며, 요청이 있을 때마다 이 컨텍스트를 통해 사용자의 정보와 권한을 확인함.

필터 체인(Filter Chain)

Spring Security는 Servlet Filter를 기반으로 동작하며, 요청이 들어올 때 필터 체인(Filter Chain)을 통해 보안 관련 작업을 처리함. SecurityFilterChain은 여러 필터로 구성되어 있으며, 각 필터는 특정 보안 작업을 처리함.

Spring Security의 주요 구성 요소

SecurityContextHolder

SecurityContextHolder는 인증된 사용자의 세부 정보를 SecurityContext에 저장함.
이를 통해 애플리케이션 어디서든 현재 인증된 사용자의 정보를 가져올 수 있음.

AuthenticationManager

AuthenticationManager는 인증 요청을 처리하는 주요 컴포넌트임.
이 컴포넌트는 인증이 성공했는지 실패했는지 여부를 결정함. 이를 위해 여러 AuthenticationProvider가 함께 동작하며, 사용자의 인증 정보를 처리함.

AuthenticationProvider

AuthenticationProvider는 사용자의 인증 정보를 확인하는 로직을 정의하는 인터페이스임.
Spring Security는 여러 AuthenticationProvider를 사용할 수 있으며, 각 Provider는 다양한 방식으로 인증을 처리할 수 있음 (예: 기본 사용자 이름/비밀번호 인증, OAuth2 인증 등).

GrantedAuthority

GrantedAuthority는 사용자가 가진 권한을 나타냄.
Spring Security에서는 권한을 문자열로 표현하며, 보통 사용자의 역할(Role)을 권한(Authority)으로 간주함. 예를 들어, ROLE_USER, ROLE_ADMIN 등의 권한이 있을 수 있음.

UserDetails

UserDetails는 Spring Security에서 사용자 정보를 캡슐화하는 인터페이스임. 인증 과정에서 사용자 정보를 UserDetails 형태로 변환하여 사용함.
이 인터페이스는 사용자의 이름, 비밀번호, 권한 등을 포함함.

PasswordEncoder

PasswordEncoder는 비밀번호를 암호화하고 검증하는 데 사용되는 인터페이스임.
기본적으로 Spring Security는 BCryptPasswordEncoder를 제공하며, 비밀번호를 암호화하여 안전하게 저장하고 검증할 수 있음.

Spring Security의 동작 원리

Spring Security의 전체적인 동작은 Servlet Filter를 통해 이루어지며, 요청이 들어올 때 Security Filter Chain을 거쳐 인증과 인가 과정을 처리하게 됨.

인증 과정

  1. 요청 처리: 클라이언트가 로그인 페이지나 API 엔드포인트에 요청을 보냄.

  2. AuthenticationManager 호출: Spring Security의 AuthenticationManager는 사용자의 인증 정보를 처리하기 위해 호출됨.

  3. AuthenticationProvider 검증: AuthenticationProvider는 사용자 정보를 검증함. (예: 사용자가 입력한 사용자명과 비밀번호가 데이터베이스와 일치하는지 확인)

  4. 인증 성공: 인증에 성공하면 SecurityContextHolder에 인증 정보를 저장하고, 이후 요청에서 이 정보를 참조할 수 있음.

인가 과정

  1. 요청 처리: 사용자가 특정 URL에 접근하려고 하면, 요청이 필터 체인을 거침.

  2. 보안 컨텍스트 확인: Spring Security는 SecurityContext에서 사용자의 인증 정보를 확인하고, 해당 사용자가 자원에 접근할 권한이 있는지 확인함.

  3. 권한 부여: 사용자가 요청한 자원에 대한 권한이 있을 경우, 요청을 허용하고, 그렇지 않으면 접근 거부(403 Forbidden)를 반환함.

필터 체인 구조

Spring Security는 필터 기반 아키텍처로 구성되어 있으며, 클라이언트의 모든 요청은 필터 체인을 통과함. 이 필터 체인에는 여러 보안 필터가 포함되어 있으며, 이 중 대표적인 필터는 다음과 같음

UsernamePasswordAuthenticationFilter: 사용자의 로그인 요청을 처리하고, 인증 정보를 확인함.

BasicAuthenticationFilter: Basic Authentication을 처리함.

ExceptionTranslationFilter: 인증이나 권한 오류가 발생할 경우, 예외를 처리하고 적절한 응답을 반환함.

FilterSecurityInterceptor: 사용자가 요청한 리소스에 대해 접근 권한을 확인함.

Spring Security의 주요 설정

Spring Security는 기본적으로 많은 보안 기능을 제공하지만, 필요에 따라 세부 설정이 필요함. Spring Security 설정은 보통 Java 설정 파일에서 이루어짐. Spring Boot에서는 SecurityFilterChain Bean 등록을 통해 설정할수 있음.

기본 설정

@Configuration
@EnableWebSecurity
public class SecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		/* requestMathcers 해당 url로 요청될시
		 * permitAll 모두 허용
		 * hasRole 1개의 사용자만 허용
		 * hasAnyRole 명시된 사용자 모두 허용
		 * anyRequest requestMatchers에 해당되지 않는 모든 uri 가장 마지막에 설정 되어야함
		 * */
		http.authorizeHttpRequests((auth) -> auth
                .requestMatchers("/login","/","/join").permitAll()
                .requestMatchers("/manager").hasAnyRole("MANAGER")
                .requestMatchers("/admin").hasAnyRole("ADMIN")
                .anyRequest().authenticated()
        );
		// 로그인 설정
		http.formLogin((auth) -> auth
				.loginPage("/login") // login이 필요한 페이지 이동시 login 안되있을시 login페이지가 뜨도록
				.loginProcessingUrl("/loginProc")
				.permitAll()
				); // login페이지에서 loginForm 의 데이터가 해당 url로 넘겨져 login실행
		//로그아웃 설정
	    http
        .logout((auth) -> auth.logoutUrl("/logout")
                .logoutSuccessUrl("/"));
		
//		http.csrf((auth) -> auth
//				.disable()
//				);
		
		// 동시 접속(중복 로그인) 세션 개수 제한
		http.sessionManagement((auth) -> auth
        		// maximumSession(정수) : 하나의 아이디에 대한 다중 로그인 허용 개수
                .maximumSessions(1)
                // maxSessionPreventsLogin(boolean) : 다중 로그인 개수를 초과하였을 경우 처리 방법
                // true : 초과시 새로운 로그인 차단
                // false : 초과시 기존 세션 하나 삭제
                .maxSessionsPreventsLogin(true));
		
		// 세션 고정 공격을 보호하기 위한 로그인 성공시 세션 설정
		http.sessionManagement((auth) -> auth
        		/*
        		 * sessionManagement().sessionFixation().none() : 로그인 시 세션 정보 변경 안함
				   sessionManagement().sessionFixation().newSession() : 로그인 시 세션 새로 생성
				   sessionManagement().sessionFixation().changeSessionId() : 로그인 시 동일한 세션에 대한 id 변경
        		 */
                .sessionFixation().changeSessionId());
		
		return http.build();
	}
	
}

사용자 정의 인증 로직

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found");
        }
        return new CustomUserDetails(user);
    }
}

UserDetailsService: Spring Security에서 사용자 인증 정보를 로드하는 인터페이스임.
loadUserByUsername(): 사용자명을 통해 데이터베이스에서 사용자 정보를 조회하고, UserDetails 객체로 반환함.

비밀번호 암호화 설정

Spring Security에서는 비밀번호를 안전하게 저장하고 인증하는 데 PasswordEncoder를 사용함. 주로 BCrypt 알고리즘이 사용됨.

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

Spring Security의 고급 기능

메소드 기반 보안

Spring Security는 메소드 수준에서의 보안도 지원함. @Secured, @PreAuthorize, @PostAuthorize 어노테이션을 사용하여 메소드 단위로 권한을 제어할 수 있음.

@Secured("ROLE_ADMIN")
public void adminMethod() {
    // 자신이 권한을 검사해주고 싶은 곳에 @Secured 애노테이션을 붙여주면, 애노테이션에 인자로 받은 권한을 갖고 있는 유저에게만 실행하도록 할 수 있음.
}

@PreAuthorize("hasRole('USER')")
public void userMethod() {
    // 사용자 권한이 있어야 접근 가능
    // @PreAuthorize: 메서드가 실행되기 전에 인증을 거침
}

@PostAuthorize("hasRole('USER')")
public void userMethod() {
    // 사용자 권한이 있어야 접근 가능
    // @PostAuthorize: 메서드가 실행되고 나서 응답을 보내기 전에 인증을 거침
}

차이점: @Secured는 표현식 사용할 수 없음.
@PreAuthroize, @PostAuthorize는 표현식 사용을 사용하여 디테일한 설정이 가능함.

OAuth2 및 JWT 지원

Spring Security는 OAuth2, JWT 등의 토큰 기반 인증도 지원함. 이를 통해 REST API 보안을 강화할 수 있음.

OAuth2는 외부 인증 서버를 통해 인증을 위임하는 방식이며, Spring Security는 이를 지원하는 Spring Security OAuth2 모듈을 제공함.
JWT(JSON Web Token)는 인증 정보와 사용자 정보를 암호화하여 토큰으로 관리하는 방식으로, Spring Security는 이를 통해 무상태(stateless) 보안을 구현할 수 있음.

Spring Boot와의 통합

Spring Boot는 Spring Security와의 통합을 매우 쉽게 해줌. Spring Boot Starter Security를 의존성에 추가하면, 기본적으로 기본 보안 설정이 자동으로 적용됨. 커스텀 설정이 필요할 때는 WebSecurityConfigurerAdapter를 상속받아 설정을 변경하면 됨.

Spring Boot 기본 보안

모든 경로가 인증을 요구함.
기본 로그인 폼이 제공됨.
기본 사용자명과 비밀번호(애플리케이션 실행 시 콘솔에 출력)가 제공됨.

결론

Spring Security는 Spring 애플리케이션에 필요한 강력한 보안 기능을 제공하며, 인증과 권한 부여를 관리하는 데 매우 유용한 도구임.

Servlet Filter를 기반으로 동작하며, 애플리케이션의 다양한 계층에서 보안 처리를 할 수 있음.

또한, 확장성이 뛰어나며, 커스터마이징이 필요한 경우에도 유연하게 대응할 수 있음.

Spring Boot와의 통합을 통해 기본적인 보안 기능을 쉽게 설정하고, 필요에 따라 고급 기능(OAuth2, JWT 등)을 추가하여 애플리케이션의 보안을 더욱 강화할 수 있음.

profile
웹개발자 취업 준비생

0개의 댓글