서론
SpringBoot 를 사용하는 백엔드에서 인증,인가,권한 에 대한 컨트롤을 하는 주체에 대해 비교하려고 한다.
두 개 모두 "사용자 관리 및 인증" 역할을 한다.
전제는 사내 SSO 오픈소스인 Keycloak 을 사용하는 경우 개별 서비스 백엔드를 SpringSecurity 로 구성하는게 좋을까?
아니면 Keycloak 을 사용하는게 좋을까?
본론
### SpringSecurity
1. 기본용어
- 접근 주체(Principal) : 보호된 리소스에 접근하는 대상
- 인증(Authentication) : 보호된 리소스에 접근한 대상에 대해 누구인지
- 인가(Authorize) : 해당 리소스에 대해 접근 가능한 권한을 가지고 있는지 확인하는 과정(After Authentication, 인증 이후) => 즉, 어떤 것을 할 수 있는지?
- 권한 : 어떠한 리소스에 대한 접근 제한, 모든 리소스는 접근 제어 권한이 걸려있음. 인가 과정에서 해당 리소스에 대한 제한된 최소한의 권한을 가졌는지 확인
2. 구조
SecurityContextPersistenceFilter | SecurityContextRepository에서 SecurityContext를 로드하고 저장하는 일을 담당함 |
LogoutFilter | 로그아웃 URL로 지정된 가상URL에 대한 요청을 감시하고 매칭되는 요청이 있으면 사용자를 로그아웃시킴 |
UsernamePasswordAuthenticationFilter | 사용자명과 비밀번호로 이뤄진 폼기반 인증에 사용하는 가상 URL요청을 감시하고 요청이 있으면 사용자의 인증을 진행함 |
DefaultLoginPageGeneratingFilter | 폼기반 또는 OpenID 기반 인증에 사용하는 가상URL에 대한 요청을 감시하고 로그인 폼 기능을 수행하는데 필요한 HTML을 생성함 |
BasicAuthenticationFilter | HTTP 기본 인증 헤더를 감시하고 이를 처리함 |
RequestCacheAwareFilter | 로그인 성공 이후 인증 요청에 의해 가로채어진 사용자의 원래 요청을 재구성하는데 사용됨 SecurityContextHolderAwareRequestFilter HttpServletRequest를 HttpServletRequestWrapper를 상속하는 하위 클래스(SecurityContextHolderAwareRequestWrapper)로 감싸서 필터 체인상 하단에 위치한 요청 프로세서에 추가 컨텍스트를 제공함 |
AnonymousAuthenticationFilter | 이 필터가 호출되는 시점까지 사용자가 아직 인증을 받지 못했다면 요청 관련 인증 토큰에서 사용자가 익명 사용자로 나타나게 됨 |
SessionManagementFilter | 인증된 주체를 바탕으로 세션 트래킹을 처리해 단일 주체와 관련한 모든 세션들이 트래킹되도록 도움 |
ExceptionTranslationFilter | 이 필터는 보호된 요청을 처리하는 동안 발생할 수 있는 기대한 예외의 기본 라우팅과 위임을 처리함 |
FilterSecurityInterceptor | 이 필터는 권한부여와 관련한 결정을 AccessDecisionManager에게 위임해 권한부여 결정 및 접근 제어 결정을 쉽게 만들어 줌 |
3. 기능, 특징
- 기본적으로 쿠키와 세션방식으로 인증 (JWT, Oauth, 2단계인증 등 제공)
- 쿠키-세션방식 인증 시 동접자가 많을경우 서버에 부담이 생김
- Filter 기반으로 동작하여 MVC와 분리하여 관리 및 동작
- 어노테이션을 통한 간단한 설정
- 권한에 따른 URI 접근제어
- 알려진 보안취약점 해결
4. 서버기반 인증 (쿠키-세션)
- 클라이언트가 로그인 요청시 서버는 인증 후 세션 생성 및 유지&응답한다. (인메모리 세션저장소인 SecurityContextHolder 에 저장)
- 클라이언트는 받은 세션ID를 쿠키에 저장한다.
- 인가가 필요한 리소스 요청시 헤더에 쿠키를 포함시켜 보낸다.
- 서버는 쿠키를 확인하여 사용자를 식별하고 적합한 리소스를 응답한다.
- 문제는 확장에 취약하다 (로드밸런싱을 통해 서버개수를 확장하였을경우 세션관리가 어려워짐.)
-> 각 서버마다 서로 다른 세션저장소를 가지기에 요청이 매번 다른 서버를 통하면 세션불일치가 발생)
-> 이를 해결할방법은 Sticky Session 이나 Session Clustering 방식을 사용하여 해결은 되지만, 관리포인트가 증가하고 버그가 발생하기 쉬운환경이 된다.)
5. 토큰기반 인증 (JWT 웹표준토큰 기반)
- 인증이후 서버측에서 유저에게 signed 토큰을 발급
- 클라이언트는 토큰을 저장해두고, 요청마다 토큰을 헤더에 담아 서버에 함께 전달
- 서버는 받은 토큰을 검증하고 요청에 응답
- 문제는 JWT 탈취시 서버에서 토큰 무력화가 어려움
-> 토큰 만료기간을 짧게 유지해야한다. (하지만 토큰이 만료될때마다 사용자는 재로그인 해야 하는 문제 발생,,)
-> 이를 해결하기 위해 만료기간이 긴 refresh token 을 함께 사용 (refresh token 은 jwt 를 재발행하기 위한 인증 토큰)
-> 참고: (spring security + jwt)
-> 토큰에 중요한 개인정보는 넣지 않는게 좋다.
-> 다중 로그인을 막기위해 결국 세션이나 다른 방법을 사용하게 된다. (이는 좀 더 리서치 필요) - 참고: k3068.tistory.com/90
6. 다른채널
- 인증, Role 관리 주체를 타채널에 맡긴다.
### Keycloak
1. 개별 앱에 대해 전체적인 관리가능 (각 앱을 클라이언트로 지칭하며 인증방식부터 다양한 설정을 제공)
2. 통합 계정 관리
3. 클라이언트별로 Role 관리
결론
사실 사내 SSO 를 오픈소스 keycloak 으로 사용하고 있다면, 어느정도 답은 정해져 있다고 본다. (keycloak)
두 툴 모두 Spring 에서 사용하기에 큰 어려움이 없어 보인다.
출처
channing.netlify.app/blog/2019/10/13/channing/
'IT > 스프링부트' 카테고리의 다른 글
Keycloak 인증이 필요한 Springboot API 를 Swagger 에서 사용해보기 (0) | 2022.12.20 |
---|---|
Forward, Redirect 간단하게 정리 (0) | 2021.07.15 |