Server🧤/SpringSecurity

[SpringSecurity] BasicAuthenticationFilter, UsernamePasswordAuthenticationFilter, CsrfFilter, RememberMeAuthenticationFilter, AnonymousAuthenticationFilter

yujindonut 2023. 7. 17. 11:15
728x90

BasicAuthenticationFilter

  • 따로 로그인이라는 과정을 하지 않았는데도 일회성으로 페이지를 불러올 수 있다. 로그인 데이터를 Base64로 인코딩해서 모든 요청에 포함해서 보내면 BasicAuthenticationFilter는 이걸 인증한다.
  • 세션이 필요 없고 요청이 올때마다 인증이 이루어 집니다. (즉 stateless합니다.)
  • 이런 방식은 요청할 때마다 아이디와 비밀번호가 반복해서 노출되기 때문에 보안에 취약
    BasicAuthenticationFilter를 사용할 때는 반드시 https를 사용하도록 권장됨
  • BasicAuthenticationFilter를 사용하지 않을 것이라면 명시적으로 disable시켜주는 것이 좋다
@Override
protected void configure(HttpSecurity http) throws Exception {
// basic authentication
http.httpBasic(); // basic authentication filter 활성화
http.httpBasic().disable(); // basic authentication filter 비활성화

 


UsernamePasswordAuthenticationFilter

 

  • ProviderManager (AuthenticationManager)
    • 인자로 받은 authentication이 유효한지 확인하고 authentication을 반환.
    • 인증하면서 계정에 문제가 있는 것이 발견되면 AuthenticationException를 throw 할 수 있다.
    • AuthenticationManager를 구현한 것이, ProviderManager
    • ProviderManager는 Password가 일치하는지, 계정이 활성화 되어있는지를 확인한 뒤 authentication을 반환한다.
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        result = provider.authenticate(authentication);
    }
}
  • DaoAuthenticationProvider(AbstractUserDetailsAuthenticationProvider)
    • 유저를 인증하기 위해서는 어쨌든 먼저 유저정보를 가져와야함
    • DaoAuthenticationProvider는 유저정보를 가져오는 Provider이다.
public abstract class AbstractUserDetailsAuthenticationProvider {
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		String username = determineUsername(authentication);
		user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
	}
}
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
	protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
		UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
		return loadedUser;
	}
}
public UserDetailsService userDetailsService() {
			return username -> {
				User user = userService.findByUsername(username);
				if (user == null) {throw new UsernameNotFoundException(username);}
				return user;
			}
}

CsrfFilter

  • CsrfFilter는 CsrfAttack을 방어하는 Filter
  • 위조된 페이지를 구분하기 위해서 CSRF토큰 진위여부를 확인하는 방법
  • Csrf Token을 사용하여 위조된 페이지의 악의적인 공격을 방어
    • 위조된 페이지를 구분하기 위해서 CSRF토큰 진위여부를 확인하는 방법
    • 정상적인 페이지는 Csrf Token이 있고, 위조된 페이지는 Csrf Token이 없거나 잘못된 Csrf Token을 가지고 있다.
    • Tymeleaf에서는 페이지를 만들때 자동으로 Csrf Token을 넣어준다.
  • Csrf Filter는 자동으로 활성화되어있는 Filter지만 명시적으로 On 하기 위해서는 http.csrf(); 코드를 추가
  • Off하기 위해서는 http.csrf().disable(); 해줍니다.

RememberMeAuthenticationFilter

  • 일반적인 세션보다 훨씬 오랫동안 로그인 사실을 기억할 수 있도록 해줍니다.
  • Session의 세션 만료 시간은 기본 설정이 30분이지만 RememberMeAuthenticationFilter의 기본 설정은 2주이다.
// rememberMe() 활성화
http.rememberMe();

<div>
	<span>로그인 유지하기</span>
	<input type="checkbox" id="remember-me" name="remember-me" class="form-check-input mt-0" autocomplete="off">
</div>

AnonymousAuthenticationFilter

  • 인증이 안된 유저가 요청을 하면 Anonymous(익명) 유저로 만들어 Authentication에 넣어주는 필터
  • 인증되지 않았다고 하더라도 Null을 넣는게 아니라 기본 Authentication을 만들어 주는 개념
  • 다른 Filter에서 Anonymous유저인지 정상적으로 인증된 유저인지 분기 처리를 할 수 있다

Anonymous유저의 SecurityContext

// anonymousAuthenticationFilter 활성화
http.anonymous().principal("anonymousUser");

FilterSecurityInterceptor 

  1. 위의 SecurityContextPersistenceFilter, UsernamePasswordAuthenticationFilter, AnonymousAuthenticationFilter 에서 SecurityContext를 찾거나 만들어서 넘겨주고 있다.
  2. FilterSecurityInterceptor에서는 위의 Filter로 넘어온 authenticaiton의 내용을 기반으로 최종 인가 판단을 내린다.
  3. 인증에 문제가 있다면 AuthenticationException를 발생한다.
  4. 인증에 문제가 없다면 해당 인증으로 인가를 판단한다. 인가가 거절된다면 AccessDeniedException를 발생시킨다.
  5. 승인된다면 정상적으로 필터가 종료

3. 아키텍처


ExceptionTranslationFilter

  • FilterSecurityInterceptor에서 발생할 수 있는 두가지 Exception을 처리해주는 필터
  • AuthenticationException : 인증에실패할때발생
  • AccessDeniedException:인가에실패할때발생
  • , 인증이나 인가에 실패했을 때 어떤 행동을 취해야하는지를 결정해주는 Filter입니다.
  • ExceptionTranslationFilterhandleSpringSecurityExceptionException의 종류에 따른 로직을 분산함.
private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response,
	FilterChain chain, RuntimeException exception) throws IOException, ServletException {
	if (exception instanceof AuthenticationException) {
		handleAuthenticationException(request, response, chain, (AuthenticationException) exception);
	} else if (exception instanceof AccessDeniedException) {
		handleAccessDeniedException(request, response, chain, (AccessDeniedException) exception)
	} 
}

 

728x90