우당탕탕 개발일지

[Spring] 🔒 스프링 시큐리티(Spring Security) 란? 본문

Spring

[Spring] 🔒 스프링 시큐리티(Spring Security) 란?

kyunge_ev 2023. 1. 3. 20:27

애플리케이션의 인증, 인가 등의 보안 기능을 제공하는 스프링 하위 프레임워크

보안 관련 된 많은 기능들을 제공하기 때문에 편리하게 원하는 기능을 설계할 수 있음

🌈 Spring Security 적용 흐름

스프링 시큐리티는 인증과 권한에 대한 부분을 Filter 흐름에 따라 처리하고 있음

Filter는 Dispatcher Servlet으로 가기 전에 적용되므로 가장 먼저 URL 요청을 받지만, 

Interceptor는 Dispatcher와 Controller 사이에 위치한다는 점에서 적용 시기의 차이가 있다.

 

 

1. 사용자가 로그인 정보와 함께 인증 요청한다.

 

2. AuthenticationFilter가 요청을 가로채고, 가로챈 정보를 통해 UsernamePasswordAuthenticationToken의 인증용 객체를 생성한다.

 

3. AuthenticationManager의 구현체인 ProviderManager에게 생성한 UsernamePasswordToken 객체를 전달한다.

 

4. AuthenticationManager는 등록된 AuthenticationProvider(s)(들)을 조회하여 인증을 요구한다.

 

5. 실제 DB에서 사용자 인증정보를 가져오는 UserDetailsService에 사용자 정보를 넘겨준다.

 

6. 넘겨받은 사용자 정보를 통해 DB에서 찾은 사용자 정보인 UserDetails 객체를 만든다.

 

7. AuthenticationProvider(s)(들)은 UserDetails를 넘겨받고 사용자 정보를 비교한다.

 

8. 인증이 완료되면 권한 등의 사용자 정보를 담은 Authentication 객체를 반환한다.

 

9. 다시 최초의 AuthenticationFilter에 Authentication 객체가 반환된다.

 

10. Authentication 객체를 SecurityContext에 저장한다.

 

최종적으로 SecurityContextHolder는 세션 영역에 있는 SecurityContext에 Authentication 객체를 저장한다.

사용자 정보를 저장한다는 것은 Spring Security가 전통적인 세션-쿠키 기반의 인증 방식을 사용한다는 것을 의미한다.

🌈 보안용어 정리

인증(authentication)

사용자가 누구인지 확인하는 단계

  • ex) 로그인
    • DB에 등록된 id, pw를 사용자가 입력한 id, pw와 비교하여 일치 여부를 확인하는 과정
    • 로그인에 성공하면 애플리케이션 서버는 응답으로 사용자에게 토큰(token)을 전달
    • 로그인에 실패하면 토큰을 전달받지 못해 리소스에 접근할 수 없게 됨

인가(authorization)

인증을 통해 검증된 사용자가 애플리케이션 내부의 리소스에 접근할 때 사용자가 해당 리소스에 접근할 권리가 있는지를 확인하는 과정

  • ex) 로그인 후 게시판 글 읽기
    • 게시판 접근 등급을 확인해 접근을 허가 or 거부
  • 사용자가 인증 단계에서 발급받은 토큰은 인가 내용을 포함하고 있음
  • 사용자가 리소스에 접근하면서 토큰을 함께 전달하면 애플리케이션 서버는 토큰을 통해 권한 유무 등을 확인해 인가를 수행함

접근 주체(principal)

  • 애플리케이션의 기능을 사용하는 주체
  • 사용자, 디바이스, 시스템 등
  • 인증 과정을 통해 접근 주체가 신뢰할 수 있는지 확인 인가 과정을 통해 접근 주체에 부여 된 권한을 확인

🌈 스프링 시큐리티 동작 구조

  • 서블릿 필터(Servlet Filter)를 기반으로 동작 → DispatcherServlet 앞에 필터가 배치되어있음
  • 필터 체인(FilterChain) : 서블릿 컨테이너에서 관리하는 ApplicationFilterChain을 의미
    • 필터 체인에서 인증, 인가를 함

더보기

📌 FilterChain 사용 종류와 실행 순서

🌈 스프링 시큐리티 설정

📚 https://mvnrepository.com/

1. spring-boot-starter-security, dependency

  • 자신의 springboot에 맞는 버전을 선택
  • build.gradle 에 복붙하여 dependency

2. 패키지, 클래스 생성

  • configuration 패키지 → SecurityConfig / EncrypatherConfig 클래스 생성

📌 용어정리

  • @Configuration
  • @EnableWebSecurity → spring MVC와 Security를 매핑해줌

3. SecurityFilterChain 재정의

  • Spring Security 5.7.0-M2 부터 WebSecurityConfigurerAdapter 클래스는 컴포넌트 기반의 보안 설정을 권장한다는 이유로 점차 사용빈도가 줄어들었다.
@Configuration
@EnableWebSecurity

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // configure HTTP security...

    }
}
  • 최근 Spring Security는 SecurityFilterChain을 재정의하여 사용하기를 권장한다.
@Configuration
@EnableWebSecurity

public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
            .httpBasic().disable()
            .csrf().disable()
            .cors().and()
            .authorizeRequests()
            .antMatchers("/api/**").permitAll()
            .antMatchers("/api/v1/users/join", "/api/v1/users/login").permitAll()
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
			.addFilterBefore(new JwtTokenFilter(userService, secretKey), UsernamePasswordAuthenticationFilter.class) //UserNamePasswordAuthenticationFilter적용하기 전에 JWTTokenFilter를 적용 하라는 뜻 입니다.
            .build();
	}
}

📌 SecurityFilterChain 용어 정리

  • httpBasic().disable()
    • UI를 사용하는 것을 기본값으로 가진 시큐리티 설정을 비활성화한다.
  • .disable()
    • 비활성화
  • csrf().disable()
    • REST API에서는 CSRF 보안이 필요 없기 때문에 비활성화함
더보기

✏ CSRF 란?
- Cross-Site-Request Forgery '사이트 간 요청 위조'

 웹 애플리케이션의 취약점 중 하나로 사용자가 자신의 의지와 무관하게 웹 애플리케이션을 대상으로 공격자가 의도한 행동을 함으로써 특정 페이지의 보안을 취약하게 한다거나 수정, 삭제 등의 작업을 하는 공격 방법

 스프링 시큐리티의 csrf() 메서드는 기본적으로 CSRF 토큰을 발급해서 클라이언트로부터 요청을 받을 떄마다 토큰을 검증하는 방식으로 동작. 브라우저 사용 환경이 아니라면 비활성화해도 크게 문제 되지 않음

  • authorizeRequest()
    • 애플리케이션에 들어오는 요청에 대해 사용 권한을 체크
  • antMatchers()
    • antPattern을 통해 권한을 설정하는 역할
    • .permitAll() : 권한을 허용
    • .authenticated() : 권한을 제한
// /api/로 시작되는 모든 경로에 대해서는 모두에게 허용
.antMatchers("/api/**").permitAll()

// 해당 경로에 대해서는 모두에게 허용
.antMatchers("/api/v1/users/join", "/api/v1/users/login").permitAll()

// 해당 API 방식의 해당 경로는 권한을 제한
.antMatchers(HttpMethod.POST,"/api/v1/**").authenticated()
  • sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    • REST API 기반 애플리케이션의 동작 방식을 설정
    • STATELESS : 세션 인증 방식을 사용하지 않음

 

👇 주의! 아래 코드의 @Bean 부분을 SecurityConfig 클래스에 작성하면 에러가 발생됨 아래의 코드와 같이 EncrypaterConfig를 사용하여 추가로 정의해줌

  • securityfilterchain을 설정해준 SecurityConfig 클래스와 분리해서 코드작성해야되는 것같음(뇌피셜)
@Configuration
public class EncrypaterConfig {
    @Bean
    public BCryptPasswordEncoder encodePwd() {
        return new BCryptPasswordEncoder();
    }

}

🌈 BCryptPasswordEncoder  클래스란?

📚 참고 블로그 : https://kimvampa.tistory.com/129

  • 스프링 시큐리티 프레임워크에서 제공하는 클래스 중 하나로 비밀번호를 암호화하는데 사용할 수 있는 메서드를 가진 클래스
  • BCrypt 해싱 함수(BCrypt hashing function)를 사용해서 비밀번호를 인코딩해주는 메서드와 사용자의 의해 제출된 비밀번호와 저장소에 저장되어 있는 비밀번호의 일치 여부를 확인해주는 메서드를 제공
  • PasswordEncoder 인터페이스를 구현한 클래스
  • 생성자의 인자 값(verstion, strength, SecureRandom instance)을 통해서 해시의 강도를 조절 가능
  • 비밀번호를 암호화 함으로써 비밀번호 데이터가 노출이 되더라도 확인하기 어렵게 만들어줌

✍ encode(java.lang.CharSequence rawPassword)

  • 패스워드를 암호화해주는 메서드
  • SHA-1, 8바이트로 결합된 해쉬, 랜덤하게 생성된 솔트(salt)를 지원
  • 반환타입 : String
  • 매개변수 : java.lang.CharSequence 타입의 데이터
  • 똑같은 패스워드를 해당 메서드를 통해 인코딩하더라도 매번 다른 인코딩 된 문자열을 반환

✍ matchers(java.lang.CharSequence rawPassword, java.lang.String encodePassword)

  • 제출된 인코딩 되지 않은 패스워드(일치여부 확인원하는 패스워드) vs 인코딩 된 패스워드
    • 일치여부를 확인해주는 메서드
  • 첫 번째 매개변수 : 일치여부를 확인하고자하는 인코딩되지 않은 메서드
  • 두 번재 매개변수 : 인코딩 된 패스워드
  • 반환타입 : boolean