Spring 입문 3-4 (Spring Security)

SJ.CHO·2024년 10월 17일

Spring Security

@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();
    }
}
  • Spring Server 환경에서 인증 및 인가를 구현해둔 프레임워크
  • Spring Security 는 필터환경에서 적용되기에 필터와의 충돌 발생가능성이 존재.

CSRF (사이트 간 요청 위조 / Cross-site request forgery) :

  • 공격자가 인증된 브라우저에 저장된 쿠키의 세션정보를 활용(탈취) 하여 웹서버에 사용자가 의도치않은 요청을 전달.
  • 쿠키기반의 취약점을 이용한 공격이기에 REST 방식의 API에서는 disable 이 가능.
  • 만약 http://example.com/user.do?cmd=user_passwd_change&user=admin&newPwd=1234 이라는 비밀번호 초기화 URL 이 존재하고 사용자가 해당메일을 읽게된다면 사용자의 비밀번호가 초기화되는 방식.
if (StringUtils.hasText(url) &&
                (url.startsWith("/api/user") || url.startsWith("/css") || url.startsWith("/js"))
        )
http.authorizeHttpRequests((authorizeHttpRequests) ->
               authorizeHttpRequests
                       .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()// resources 접근 허용 설정
                       .requestMatchers("/api/user/**").permitAll() // `/api/user~` 의 요청 모두허용
                       .anyRequest().authenticated() // 그 외 모든 요청 인증처리
       );
  • 기존의 If문과 URL로 인증처리의 유무를 제어했다면 메소드로 손쉽게 지정이 가능하다.

  • 스프링 시큐리티는 기본적으로 로그인에 대한 폼을 제공한다.
  • 또한 SESSION 방식으로 구현된다.

기본 구조

  • Spring에서 모든 호출은 DispatcherServlet을 통과하게 되고 이후에 각 요청을 담당하는 Controller 로 분배
  • 각 요청에 대해서 공통적으로 처리해야할 필요가 있을 때 DispatcherServlet 이전에 단계가 필요하며 이것이 Filter 이다.
  • Spring Security 는 FilterChainProxy 를 통해 로직을 구현한다.

  • Form Login 인증 : 인증이 필요한 URL 요청이 들어왔을 때 인증이 되지않았다면 로그인 페이지를 반환한다.

  • UsernamePasswordAuthenticationFilter
    • AbstractAuthenticationProcessingFilter 을 상속하는 필터
    • 기본적으로 UserName 과 Password 를 이용한다.
    • 사용자가 정보를 제출하게 된다면 해당 필터는
      UsernamePasswordAuthenticationToken 유저 정보 토큰을 만들어 매니저에게 인증을 시도
    • 성공시 해당 토큰을 SecurityContextHolder 에 세팅
    • 실패시 SecurityContextHolder 을 비운다.
  • SecurityContextHolder
    • 인증이 완료된 사용자의 토큰을 장착한다.
    • SecurityContextHolder 를 통해 접근이 가능하다.
// 예시코드
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, credentials, authorities);
context.setAuthentication(authentication); // SecurityContext 에 인증 객체 Authentication 를 저장합니다.

SecurityContextHolder.setContext(context);
  • Authentication
    • principal : 사용자를 식별, UserDetails 객체를 집어넣음
    • credentials : 주로 비밀번호를 삽입, 사용자 인증 후 비움.
    • authorities : 사용자 권한을 추상화하여 사용
<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());
  • UserDetailsService : 사용자를 조회하고 검증한 후 UserDetails 객체 반환. 커스텀하여 Bean으로 사용가능.

  • UserDetails : 검증된 유저의 정보객체. SecurityContextHolder 세팅되어 사용된다.

Spring Security 로그인

  • Client의 요청은 전부 Spring Securit 를 거치게됨.

profile
70살까지 개발하고싶은 개발자

0개의 댓글