[SPRING] Spring Security

야부엉·2023년 11월 13일
0

1. Spring Security

1. 개념

  • Spring 서버에 필요한 인증/인가를 위해 많은 기능을 제공해주는 프레임워크
  • 추가 방법은 build.gradle > dependecy에 아래 코드 추가하면 된다.
// Security
implementation 'org.springframework.boot:spring-boot-starter-security'

2. 설정

  • WebSecurityConfig 파일
@Configuration
@EnableWebSecurity // Spring Security 지원을 가능하게 함
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // CSRF 설정
        http.csrf((csrf) -> csrf.disable());

        http.authorizeHttpRequests((authorizeHttpRequests) ->
                authorizeHttpRequests
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // resources 접근 허용 설정
                        .anyRequest().authenticated() // 그 외 모든 요청 인증처리
        );

        // 로그인 사용
        http.formLogin(Customizer.withDefaults());

        return http.build();
    }
}
  • filter에 적용된 @component 어노테이션을 지워야한다.

3.CRSF(Cross-site request forgery)

  • 사이트 간 요청 위조로 공격자가 인증된 브라우저에 저장된 쿠키의 세션 정보를 활용하여, 웹 서버에 사용자가 의도하지 않은 요청을 전달하는 것
  • CSRF 설정이 되어있을 경우 html에서 CSRF 토큰 값을 넘겨주어야 요청을 수신을 가능하다.
  • 쿠키 기반의 취약점을 이용한 공격이기 때문에 rest 방식의 api에서는 disable 가능

2. Spring Security 이해하기

1. Spring Security - Filter Chain

  • Spring Security도 인증/인가를 처리하기 위해 Filter를 사용한다.
  • FilterChainProxy를 통해서 상세로직을 구현하고 있다.

2. Form Login 기반 인증

  • 인증이 필요한 URL 요청이 들어왔을 때 인증이 되지 않았다면 로그인 페이지를 반환하는 형태

3. UsernamePasswordAuthenticationFilter

  • UsernamePasswordAuthenticationFilter는 Spring Security의 필터인 AbstractAuthenticationProcessingFilter를 상속한 Filter다.
  • Form Login일 경우 username과 password를 확인하여 인증을 하는데, 인증 과정은 아래와 같다.
  1. 사용자가 username과 password를 제출하면 UsernamePasswordAuthenticationFilter는 인증된 사용자의 정보가 담긴 UsernamePasswordAuthentcaionToken을 만들어 AuthenticationManager에게 넘겨 인증을 시도한다.
  2. 실패하면 SecurityContextHolder를 비운다.
  3. 성공시 SecurityContextHolder에 Authentcation 세팅 한다.

4. SecurityContextHolder

  • 인증이 완료된 사용자의 상세정보(Authentication)를 저장한다.
  • SecurityContext는 SecurityContextHolder를 이용해서 접급한다.
// 예시코드
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, credentials, authorities);
context.setAuthentication(authentication); // SecurityContext 에 인증 객체 Authentication 를 저장합니다.

SecurityContextHolder.setContext(context);

5. Authentication

  • SecurityContext에서 가져 올 수 있다.
  • principal : 사용자를 식별
    - Username/Password 방식으로 인증할 때 일반적으로 UserDetails 인스턴스
  • credentials : 주로 비밀번호를 담는다. 대부분 사용자 인증에 사용한 후 비운다.
  • authorities : 사용자에게 부여한 권한을 GrantedAuthority로 추상화하여 사용
<UserDetails>
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    UserRoleEnum role = user.getRole();
    String authority = role.getAuthority();

    SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
    Collection<GrantedAuthority> authorities = new ArrayList<>();
    authorities.add(simpleGrantedAuthority);

    return authorities;
}

Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

3. Spring Security : 로그인

1.Spring Security 처리 과정

  • client 요청은 모두 Spring Security를 거치게 된다.
  • Spring Security 역할(인증/인가)
    - 성공 시 Controller로 Client 요청{Client 요청 + 사용자 정보(=UserDetails)} 전달
    - 실패 시 Cilent에게 Error Response 보냄

2. 로그인 처리 과정 상세

  • Client
    - username, password 정보를 HTTP body로 전달(Post)

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
       // CSRF 설정
       http.csrf((csrf) -> csrf.disable());
    
       http.authorizeHttpRequests((authorizeHttpRequests) ->
               authorizeHttpRequests
                       .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // resources 접근 허용 설정
                       .anyRequest().authenticated() // 그 외 모든 요청 인증처리
       );
    
       // 로그인 사용
    	 http.formLogin((formLogin) ->
               formLogin
                    // 로그인 처리 (POST /api/user/login)
                   .loginProcessingUrl("/api/user/login").permitAll()
       );
    
       return http.build();
    }
  • 인증 관리자(Authentication Manager)
    - UserDetailsService 에게 username 을 전달하고 회원상세 정보를 요청

  • UserDetailsService
    - 회원 DB에서 회원 조회

    User user = userRepository.findByUsername(username)
        .orElseThrow(() -> new UsernameNotFoundException("Not Found " + username));
- 조회된 회원 정보를 UserDetails로 반환
UserDetails userDetails = new UserDetailsImpl(user)
- UserDetails 를 "인증 관리자"에게 전달
  • 인증 관리자가 인증 처리
  1. 아래 2 개의 username, password 일치 여부 확인
    1. Client 가 로그인 시도한 username, password
    2. UserDetailsService 가 전달해준 UserDetails 의 username, password
  2. password 비교 시
    1. Client 가 보낸 password 는 평문이고, UserDetails 의 password 는 암호문
    2. Client 가 보낸 password 를 암호화해서 비교
  3. 인증 성공 시 → 세션에 로그인 정보 저장
  4. 인증 실패 시 → Error 발생

출처

내일배움캠프 Spring Master

profile
밤낮없는개발자

0개의 댓글