일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- C
- Algorithm
- Data Structure
- JavaScript
- 디자인 패턴
- Java
- mongoDB
- JPA
- Galera Cluster
- OS
- spring webflux
- 자료구조
- 백준
- 네트워크
- 파이썬
- MSA
- MySQL
- 운영체제
- Spring
- 자바
- IT
- 알고리즘
- Kafka
- Heap
- Proxy
- react
- 컴퓨터구조
- c언어
- redis
- design pattern
Archives
- Today
- Total
시냅스
Spring Security 공식 문서 기반 정리 본문
Spring Security가 framework로 하는 일
- ServletContext 내부로 가지 않고 Filter 수준에서 보안을 설정한다.
- 어플리케이션의 모든 상호작용에 사용자 인증 요구
- 디폴트 로그인 폼 생성
- user 라는 이름과 콘솔에 출력한 비밀번호를 사용한 폼 기반 인증 지원
- BCrypt로 저장할 비밀번호 보호
- 사용자 로그아웃 지원
- CSRF 공격 방어
- Session Fixation 방어
- 보안 헤더 통합
- HTTP Strict Transport Security로 요청을 보호
- X-Content-Type-Options 통합
- Cache Control (어플리케이션에서 특정 스태틱 리소스에 캐시를 허용하도록 재정의할 수 있다.)
- X-XSS-Protection 통합
- X-Frame-Options 통합으로 클릭재킹 방어 지원
- 서블릿 API 메소드 통합
- HttpServletRequest#getRemoteUser()
- HttpServletRequest.html#getUserPrincipal()
- HttpServletRequest.html#isUserInRole(java.lang.String)
- HttpServletRequest.html#login(java.lang.String, java.lang.String)
- HttpServletRequest.html#logout()
서블릿 Filter 와 Spring Security
- 스프링 부트는 DelegatingFilterProxy 라는 filter 구현체로 서블릿 컨테이너의 생명주기와 스프링의 ApplicationContext를 연결한다.
- 서블릿 컨테이너는 자체 표준을 사용해서 Filter를 등록할 수 있지만 스프링이 정의하는 빈은 인식하지 못한다.
- DelegatingFilterProxy는 표준 서블릿 컨테이너 메커니즘으로 등록할 수 있으면서도, 모든 처리를 Filter를 구현한 스프링 빈으로 위임한다.
- 위의 figure는 DelegatingFilterProxy가 어떻게 여러 Filter로 구성된 FilterChain에 껴들어 가는지 보여준다.
- 스프링 시큐리티는 FilterChainProxy로 서블릿을 지원한다.
- FilterChainProxy는 스프링 시큐리티가 제공하는 특별한 Filter로 SecurityFilterChain을 통해 여러 Filter 인스턴스로 위임할 수 있다.
- FilterChainProxy는 보통 빈이기 때문에 DelegatingFilterProxy로 감싸져 있다.
- SecurityFilterChain에 있는 보안 필터들은 전형적인 빈이지만 DelegatingFilterProxy가 아닌 FilterChainProxy로 등록한다.
- 스프링 시큐리티가 서블릿을 지원할 수 있는 시작점이 되기 위해
- SecurityFilterChain 을 어떨 때 실행할지 유연하게 결정하기 위해
- 실행여부를 HttpServletRequest를 통해 결정할 수 있다.
- 아래는 스프링 시큐리티 필터 목록이다.
- HeaderWriterFilter : Http 해더를 검사한다. 써야 할 건 잘 써있는지, 필요한 해더를 더해줘야 할 건 없는가?
- CorsFilter : 허가된 사이트나 클라이언트의 요청인가?
- CsrfFilter : 내가 내보낸 리소스에서 올라온 요청인가?
- LogoutFilter : 지금 로그아웃하겠다고 하는건가?
- UsernamePasswordAuthenticationFilter : username / password 로 로그인을 하려고 하는가? 만약 로그인이면 여기서 처리하고 가야 할 페이지로 보내 줄께.
- ConcurrentSessionFilter : 여거저기서 로그인 하는걸 허용할 것인가?
- BearerTokenAuthenticationFilter : Authorization 해더에 Bearer 토큰이 오면 인증 처리 해줄께.
- BasicAuthenticationFilter : Authorization 해더에 Basic 토큰을 주면 검사해서 인증처리 해줄께.
- RequestCacheAwareFilter : 방금 요청한 request 이력이 다음에 필요할 수 있으니 캐시에 담아놓을께.
- SecurityContextHolderAwareRequestFilter : 보안 관련 Servlet 3 스펙을 지원하기 위한 필터라고 한다.(?)
- RememberMeAuthenticationFilter : 아직 Authentication 인증이 안된 경우라면 RememberMe 쿠키를 검사해서 인증 처리해줄께
- AnonymousAuthenticationFilter : 아직도 인증이 안되었으면 너는 Anonymous 사용자야
- SessionManagementFilter : 서버에서 지정한 세션정책을 검사할께.
- ExcpetionTranslationFilter : 나 이후에 인증이나 권한 예외가 발생하면 내가 잡아서 처리해 줄께.
- FilterSecurityInterceptor : 여기까지 살아서 왔다면 인증이 있다는 거니, 니가 들어가려고 하는 request 에 들어갈 자격이 있는지 그리고 리턴한 결과를 너에게 보내줘도 되는건지 마지막으로 내가 점검해 줄께.
- 그 밖에... OAuth2 나 Saml2, Cas, X509 등에 관한 필터들도 있습니다.
AccessDeniedHandler
- ExceptionTranslationFilter는 AccessDeniedException을 해석하고 AuthenticationException을 Http 응답으로 바꿔준다.
- 먼저 ExceptionTranslationFilter는 FilterChain.doFilter(request, response)를 호출해서 어플리케이션의 나머지 로직을 실행한다.
- 인증받지 않은 사용자였거나 AuthenticationException이 발생했다면 인증을 시작한다.
- SecurityContextHolder를 비운다.
- requestCache에 HttpServletRequest를 저장한다. 사용자 인증에 성공하면 RequestCache로 기존 요청 처리를 이어간다.
- AuthenticationEntryPoint는 클라이언트에 credential을 요청할 때 사용한다.
- 반대로 AccessDeniedException 이었다면 접근을 거부한다. 거절된 요청은 AccessDeniedHandler에서 처리한다.
Spring Security Authentication - Architecture Componenets
- SecurityContextHolder
- 스프링 시큐리티에서 인증한 대상에 대한 상세 정보
- SecurityContext
- 현재 인증한 사용자의 Authentication을 가지고 있다.
- Example. Setting SecurityContextHolder
SecurityContext context = SecurityContextHolder.createEmptyContext(); // (1)
Authentication authentication =
new TestingAuthenticationToken("username", "password", "ROLE_USER"); // (2)
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context); // (3)
- 비어있는 SescurityContext를 만든다.
- Authentication 객체를 만든다.
- 실제로는 TestingAuthenticationToken 대신 UsernamePasswordAuthenticationToken(userDetails, password, authorities) 를 주로 사용한다.
- SecurityContextHolder에 SecurityContext를 설정한다.
- Example. Access Currently Authenticated User
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
- SecurityContextHolder는 ThreadLocal을 사용해 정보를 저장하기 때문에 메소드에 직접 SecurityContext를 넘기지 않아도 동일한 스레드라면 SecurityContext에 접근할 수 있다.
- 스프링 시큐리티의 FilterChainProxy는 항상 SecurityContext를 비워준다.
- Authentication
- 현재 인증된 결과
- 인증하기 위한 정보, 인증을 받기 위한 정보
- 객체로 관리한다.
- credentials
- 인증을 받기 위해 필요한 정보, 비밀번호 등 (input, AuthenticationProvider에서의 input)
- Principal
- 인증된 결과, 인증 대상 (output, AuthenticationProvider에서의 output)
- 보통 UserDetails 인스턴스다.
- Details
- 기타 정보, 인증에 관여된 주변 정보들
- Authorities
- 권한 정보들
- Authentication을 구현한 객체들은 token 이라는 이름의 객체로 구현된다. 따라서 구현체를 인증 토큰이라고 불러도 좋다.
- Authentication 객체는 SecurityContextHolder를 통해 세션이 없어도 언제든 접근할 수 있도록 필터 체인에서 보장한다.
- GrantedAuthority
- Authentication에서 접근 주체(principal)에 부여한 권한
- Authentication.getAuthorities() 메소드로 접근할 수 있다.
- AuthenticationManager
- 인증 제공자들을 관리하는 인터페이스
- 구현 객체는 ProviderManager
- 복수개 존재할 수 있다.
- 실제 수행은 AuthenticationProvider에서 한다
- AuthenticationProvider
- Authentication을 받아서 인증하고 인증된 결과를 다시 Authentication 객체로 전달한다.
- 인증 대상과 방식이 다양할 수 있기 때문에 인증 제공자도 여러개 올 수 있다
Form Login
- html 폼 기반 사용자 이름/비밀번호 인증
- 사용자가 권한이 없는 리소스 /private 에 인증되지 않은 요청을 보낸다.
- 스프링 시큐리티의 FilterSecurityInterceptor에서 AccessDeniedException을 던져 인증되지 않은 요청을 거절했음을 알린다.
- 인증되지 않은 사용자이므로 ExceptionTranslationFilter에서 인증을 시작하고, 설정한 AuthenticationEntryPoint로 로그인 페이지로의 리다이렉트 응답을 전송한다.
- 그러면 브라우저는 리다이렉트된 로그인 페이지를 요청한다.
- 어플리케이션에서 로그인 페이지를 렌더링해야 한다.
- DaoAuthenticationProvider
- UserDetailsService와 PasswordEncoder로 username/password를 인증하는 AuthenticationProvider 구현체
- UsernamePasswordAuthenticationToken을 ProviderManager로 넘긴다.
- ProviderManager는 DaoAuthenticationProvider를 사용하도록 설정 돼 있다.
- DaoAuthenticationProvider는 UserDetailsService에서 UserDetails를 조회한다.
- DaoAuthenticationProvider는 이전 단계에서 얻은 UserDetails에 있는 비밀번호를 PasswordEncoder로 검증한다.
- 인증에 성공하면 UsernamePasswordAuthenticationToken 타입의 Authentication을 반환하며, 이 객체는 UserDetailsService가 리턴한 UserDetails를 Principal로 가지고 있다.
- UsernamePasswordAuthenticationToken 는 인증 Filter에서 SecurityContextHolder로 세팅된다.
- UserDetails
- UserDetailService가 리턴하는 값
- DaoAuthenticationProvider가 Userdetails를 인증하고, UserDetails를 principal로 가진 Authentication을 리턴한다.
- UserDetailService와 UserDetails 구현체를 구현하면 스프링 시큐리티가 나머지는 쉽게 쓸 수 있도록 도와줌
- UserDetailsService
- DaoAuthenticationProvider가 username/password로 인증할 때 필요한 username, password와 다른 속성을 조회할 때 사용한다.
- 커스텀 인증을 정의하려면 커스텀 UserDetailsService를 빈으로 만들면 된다.
- PasswordEncoder
- 서블릿에서 스프링 시큐리티를 사용하려면 PasswordEncoder를 통합해 비밀번호를 안전하게 저장할 수 있다.
Comments