240301 TIL #335 Spring Security

김춘복·2024년 3월 1일
0

TIL : Today I Learned

목록 보기
335/494

Today I Learned

Spring Security에 대해 제대로 정리해본 적이 없어서 이번 기회에 정리해보려 했다.


Spring Security

: Spring 서버에 필요한 인증 및 인가를 위해 많은 기능을 제공해 개발에 편의를 제공.
(스프링 프레임워크가 웹서버 구현에 편의를 제공해주는 것과 같다.)

적용 방법

  • build.gradle
// 스프링 시큐리티
implementation 'org.springframework.boot:spring-boot-starter-security'
  • 활성화 하기 : WebSecurityConfig 클래스 생성 후 아래 내용(springboot 2.7이상)
    SpringBoot 3v 이상은 authorizeRequests() → authorizeHttpRequests()
@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // CSRF 설정
        http.csrf().disable();
        // SpringBoot 3v 이상은 authorizeRequests() → authorizeHttpRequests()
        http.authorizeRequests().anyRequest().authenticated();

        // 로그인 사용
        http.formLogin();
        
        return http.build();
    }

}
  • CSRF : Cross-site request forgery, 사이트 간 요청 위조.
    인증된 브라우저에 저장된 쿠키의 세션정보를 공격자가 활용해 웹서버에 사용자가 의도하지 않은 요청을 전달하는 것.
    CSRF 설정이 되어있는경우 html에서 CSRF 토큰값을 넘겨주어야 요청을 수신 가능.
    쿠키기반 취약점을 이용한 공격이라 REST방식 API에서는 disable 가능.
    (실습에서는 Post 요청마다 처리해주는 대신 CSRF protection 을 disable)

주요 Component

  • Spring Security 와 Filter

    Spring Security는 요청이 들어오면 Servlet FilterChain을 자동으로 구성해 거치게 한다.
    Filter는 톰캣과 같은 웹 컨테이너에서 관리되는 Servelet의 기술로 Client 요청이 전달되기 전후로 URL 패턴에 맞는 모든 요청에 필터링을 해준다. 클라이언트의 Request가 Controller까지 오기 전에 많은 필터를 거쳐서 오는 것. CSRF, XSS등의 보안검사로 올바른 요청이 아닌 것을 차단해준다. Spring Secutiry는 Filter를 사용해 인증/인가를 구현한다.
    여러 Filter를 chain형태로 묶어 놓은 것이 FilterChain.

  • SecurityFilterChain
    Spring의 보안 Filter를 결정하는데 사용되는 Filter.
    세션, JWT등의 인증방식을 사용하는데 필요한 설정을 완전히 분리할 수 있는 환경을 제공한다.
    Request는 많은 SecurityFilter를 거쳐 Controller로 가는데 일단은 아래의 것들만 살펴보기로 한다.

  • AbstractAuthenticationProcessingFilter
    사용자의 credential을 인증하기 위한 베이스 Filter
    (SecurityFilterChain 안에서 사용자 인증을 처리하는 필터)

  • UsernamePasswordAuthenticationFilter
    위의 AbstractAuthenticationProcessingFilter를 상속한 Filter.
    기본적으로 아래와 같은 Form Login 기반을 사용할 때 username과 password를 확인하여 인증.

    Form Login 기반은 인증이 필요한 URL요청이 들어왔을때(1) 인증이 되지 않았다면 AccessDeniedException을 통해(2) 로그인 페이지를 반환(3)하는 형태.

  • SecurityContextHolder

    스프링 시큐리티로 인증을 한 사용자의 상세정보를 가지고있는 SecurityContext를 담고있는 Holder. 이걸로 인증이 된 객체를 가지고 올 수 있다. (위의 필터에서 사용됨)
    SecurityContext는 SecurityContextHolder로 접근할 수 있고 Authentication 객체를 가진다.

// 예시코드
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, credentials, authorities);
context.setAuthentication(authentication);

SecurityContextHolder.setContext(context);
  • Authentication : (인증 객체) principal, credentials, authorities 3가지 정보를 가지고있다.
    현재 인증이 된 사용자를 나타내며 SecurityContext에서 가져올 수 있다.

    principal - 사용자를 식별. Username/Password 방식으로 인증할 때 보통 UserDetails 인스턴스를 가지고 있다.
    credentials - 주로 비밀번호를 뜻함. 대부분 사용자 인증에 사용한 다음 비운다.
    authorities - 사용자에게 부여한 권한을 GrantedAuthority로 추상화해 사용.

<UserDetails>
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    // 아래줄처럼 사용자 권한을 가져 와서
    UserRoleEnum role = user.getRole();
    // String으로 된 authority값에 넣어주고
    String authority = role.getAuthority();
    System.out.println("authority = " + authority);
		
    // authority를 GrantedAuthority로 한번 감싸줘서
    SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
    Collection<GrantedAuthority> authorities = new ArrayList<>();
    // 감싸준 것을 넣어서 authorities로 반환.
    authorities.add(simpleGrantedAuthority);
    return authorities;
} 
/*
인증 객체(Authentication)를 만들때 UsernamePasswordAuthenticationToken을 사용
파라미터 순서가 principal, credentials, authorities
UsernamePasswordAuthenticationToken은 인증객체(Authentication)를 만드는데 사용되는데
Authentication을 구현한 AbstractAuthenticationToken의 하위클래스이다.
*/
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
  • UserDetailsService
    username/password 인증방식 사용할 때, 사용자를 조회하고 검증한 후 UserDetails를 반환한다. Custom해서 Bean으로 등록 후 사용이 가능하다.

  • UserDetails
    검증된 UserDetails는 UsernamePasswordAuthenticationToken 타입의 Authentication을 만들때 사용되고, 해당 인증객체는 SecurityContextHolder에 세팅된다. Custom해서 사용 가능.

profile
꾸준히 성장하기 위해 매일 log를 남깁니다!

0개의 댓글