코드스테이츠 수강 16주차 1일차에는 Spring Security 기초에 대해 배웟다.
1. Spring Security란?
이전까지 우리가 실습한 프로젝트에서는 사실 로그인 기능이 없었다.
그냥 회원등록, 주문등록 등의 API을 HTTP요청에 따라 보내기만 하면 데이터베이스에 반영되게끔 했었다.
당연히 이 상태로 두면 누군가 이 프로젝트에서 사용하는 맴버변수명만 알면 이것저것 등록해서 지금까지 잘나가던 마카롱집 메뉴판을 덕춘할매 양갱집처럼 바꿔버릴 수도 있다는 것이다.
이를 방지하기 위해 보안 기능이 필요하다.
스프링에서는 자체적으로 Spring Security를 제공한다.
Spring MVC기반의 애플리케이션 인증과 인가(권한 부여)기능을 지원하는 보안 프레임 워크이다.
사실상 Spring MVC기반 애플리케이션에서 표준으로 사용된다고 한다.
Spring Security로 할 수 있는 보안 기능
- 다양한 유형(폼 로그인 인증, 토큰 기반 인증 등)의 사용자 인증 기능 적용
- 애플리케이션 사용자의 역할(사용자, 관리자 등등)에 따른 권한 레벨 적용
- 애플리케이션에서 제공하는 리소스에 대한 접근 제어
- 민감한 정보에 대한 데이터 암호화
- SSL적용
- 일반적으로 알려진 웹 보안 공격 차단
이 외에 SSO 클라이언트 인증성 기반 인증, 메서드 보안 등의 보안을 위한 대부분의 기능을 제공한다.
Spring Security에서 사용하는 용어
- Principal(주체) : Spring Security에서 사용되는 Principal은 애플리케이션에서 작업을 수행 할 수 있는 사용자, 디바이드, 시스템 등이 있으며, 일반적으로 인증 프로세스가 성공적으로 수행된 사용자의 "계정 정보"를 의미
-> 요약하면 어플리케이션을 사용할 수 있도록 허가된(인증된)놈(사용자, 전자기기 등등)의 정보 - Authentication(인증) : Authentication은 애플리케이션을 사용하는 사용자가 본인이 맞음을 증명하는 절차를 의미
(쉽게 말하면 어디 들어갈때 신분증 제시하는거)
Authentication을 정상적으로 수행하기 위해서는 식별을 위한 정보가 필요한데(신분증) 이를 Credential(신원 증명 정보) 이라고 한다. - Authorization(인가 또는 권한 부여) : Authorization(권한 부여)은 Authentication(인증)이 정상적으로 수행된 사용자에게 하나 이상의 권한을 부여하여 특정 애플리케이션의 특정 리소스에 접근 할 수 있게 허가하는 과정을 의미
(제시한 출입증(인증)에 따라 일반석, 로얄석 등의 좌석을 안내하는 공연장을 생각하자)
Authorization(권한 부여)은 반드시 Authentication(인증) 과정 이후에 수행되어야 하며, 권한은 일반적으로 역할(Role, 사용자 역할, 관리자 역할...)형태로 부여된다.
(출입증도 확인 안하고 그냥 아무나 관리자실에 들여보내주지 않듯이, 먼저 신분확인(인증)부터함) - Access Control(접근 제어): Access Control은 사용자가 애플리케이션 리소스에 접근하는 행위를 제어하는것을 의미
(싹다 들여다 볼 수 있으면 개인정보, 혹은 영업비밀, 보안 다 털림)
2. Spring Security의 웹 요청 처리 흐름
Spring Security를 요약해서 말하면, "그냥 Spring Security에서 제공하는 컴포넌트 들이 알아서 사용자 인증, 권한처리를 해준다." 라고 요약 가능하다.
"그러면 어차피 Spring Security에 짬때리면 알아서 해주는데 이걸 알아야됨?" 이라고 할 수도 있다.
알아야 된다. 흐름을 모르면 이슈 터졋을때 어디가 고장났는지, 어딜 수정해야 하는지 감도 못잡는다 -> 디버깅을 하기 위해 알아야 한다.
Spring Security는 일반적인 웹 요청 처리 + Spring Security에서 지원하는 Filter의 역할이 더해져 보안기능을 만들어 준다.
일단 일반적인 처리 흐름을 보자
보안이 적용된 웹 요청의 일반적인 처리 흐름
위의 그림은 보안이 적용된 환경에서 사용자의 웹 요청에 대한 처리 흐름을 보여준다.
- (1)에서 사용자가 보호된 리소스를 요청
- (2)에서 인증 관리자 역할을 하는 컴포넌트가 사용자의 크리덴셜(Credential)(비밀번호)을 요청
(사용자 크리덴셜은 사용자 증명을 위한 수단을 의미한다. 여기서는 미빌번호가 그 수단이 된다.) - (3)에서 사용자는 인증 관리자에게 크리덴셜(비밀번호)를 제공한다.
- (4)에서 인증 관리자는 크리덴셜 저장소에서 사용자의 크리덴셜을 조회한다.
- (5)에서 인증 관리자는 사용자가 제공한 크리덴셜과 저장되어 있는 크리덴셜을 비교해 검증작업 수행
(물론 이전에 배운 암호화된 비밀번호가 저장되어 있을 것이고, 사용자가 비번 치면 해싱된 비빌번호화 대조하는 것) - (6) 유요한 크리덴셜이 라니라면 Exception을 throw합니다.
(비밀번호 틀렷다고 알려줌) - (7) 유효한 크리덴셜이라면 (8) 에서 접근 결정 관리자 역할을 하는 컴포넌트 사용자가 적절한 권한을 부여받았는지 검증
(비밀번호 패스, 얘가 관리자인지 사용자인지 신분 확인) - (9) 적절한 권한을 부여받지 못한 사용자라면 Exception을 throw
(사용자, 관리자 등의 권한이 없는경우 로그인 실패 (블락 걸린놈 로그인 하는 경우 생각하면 좋을듯?)) - (10) 적절한 권한을 부여 받은 사용자일 시 보호된 리소스 접근 허용
이거는 일반적인 사용자 요청에 따른 흐름이고, 앞에서 설명할때 "Spring Security에서 지원하는 Filter"가 더해진다고 했다.
이렇게 요청을 보낼 때, 사용자 요청이 Contriller 같은 엔드포인트를 거쳐서 리소스까지 갔다가 인증 안됫네? 하고 빠꾸먹고 하면 낭비다 낭비
그래서 서블릿 필터를 이용해서 클라이언트 -> 비즈니스 로직으로 요청을 보내는 도중에 가로채서 필터를 동작시킨다.
(자판기에 구겨진 지폐를 막 넣는게 아니고, 넣기 전에 구겨졋는지 확인하고 넣는것을 생각하면 된다. 나(클라이언트) -> 자판기(서버, 비즈니스 로직))
웹 요청에서의 서블릿 필터와 필터 체인의 역할
앞서서 비즈니스 로직에 도달하기 전에 먼저 확인하는게 서블릿 필터 라고 했다.
필터 체인은 필터를 줄줄줄 엮어 놓은건데, 그냥 확인하는 절차가 여러개 있다고 보면 된다.
위의 그림을 보면, Filter 마다 doFilter()메서드가 있는 것을 볼 수 있다.
필터를 쓰려면 doFilter()메서드를 구현하고, 해당 메서드를 호출하는 것을 필터 체인을 만들 수 있다.
이 필터들이 이캐캐캐캐 들어온 정보들 잘 이캐캐 해주면 HttpServlet을 거쳐 DispatcherServlet에 요청이 전달이 전달되는 것이고, 반대로 DispatcherServlet에서 클라이언트로 정보를 줄 때도 필터를 거쳐서 이캐캐 간다.
그러면 계속 말하는 이캐캐 라는 작업은 뭘까 싶을 수 있는데, 그냥 보안처리라고 생각하면 된다.
Spring Security에서의 필터 역할
위의 그림에서 DelegatingFilterProxy, FilterChainProxy를 볼 수 있는데, 이 두 프록시는 클래스로, Filter인터페이스를 구현하는용도로 사용되기 때문에 서블릿 필터의 역할을 한다.
DelegatingFilterProxy, FilterChainProxy는 좀 특별한 기능을 하기때문에 저렇게 따로 그려준거다.
DelegatingFilterProxy
서블릿 필터와 연결되는 Spring Security의 필터를 ApplicationContext에 Bean으로 등록해서 사용하는데, DelegatingFilterProxy가 이 Bean을 사용하는곳의 시작점이다.
DelegatingFilterProxy는 보안이 목적이 아니고, 서블릿 컨테이너 영역의 필터와 ApplicationContext에 Bean으로 등록된 필터들을 연결해주는 브릿지 역할을 한다.
FilterChainProxy
FilterChainProxy가 바로 보안을 위한 작업을 처리하는 필터의 모음이다.
앞에서 Spring Security가 보안기능을 제공한다고 햇엇는데, 여기 있는 FilterChainProxy가 그 기능중 일부인 것이다.
Spring Security의 Filter Chain은 URL에 따라 여러개 등록 할 수 있는데, 이때 어떤 Filter Chain을 사용할지는 FilterChainProxy가 결정하며, 가장 먼저 매칭된 Filter Chain을 실행한다.
3. Spring Security의 인증 처리 흐름
앞에서는 Spring Security의 Filter Chain을 통해 보안 작업을 처리한다고 했다.
그러면, 인증 요청이 전달 된 후 뭘하나?
Spring Security의 컴포턴트 관점에서의 인증 처리 흐름
위의 그림은 일반적으로 로그인 인증처리 할 때의 흐름을 나타낸다.
- (1)에서 사용자가 로그인 폼을 이용해서 로그인 아이디, 비밀번호를 포함한 요청을 전송한다.
(UsernamePasswordAuthenticationFilter가 해당 요청을 전달받음) - 요청을 전달받은 UsernamePasswordAuthenticationFilter는 아이디(Username) 비밀번호(Password)를 이용해 (2)와 같이 UsernamePasswordAuthenticationToken을 생성
- (3 )아직 인증되지 않은 Authentication(인증,신분증)을 가지고 있는 UsernamePasswordAuthenticationFilter는 해당 Authentication(신분증)을 AuthenticationManager으로 전달한다.
AuthenticationManager를 구현한 클래스가 ProviderManager이며, 사실상 신분증 받아서 다른사람한테 처리하라고 던진것이다.
(신분증을 받긴 했는데 읽어보고 누구이구나 하고 알진 못한 상태, 검사하는 사람(ProviderManager)한테 패스) - (4)와 같이 ProviderManager(신분증 검사자)로 부터 Authentication(신분증)을 건내받은 AuthenticationProvider(신분증을 꼼꼼히 아주 막 들여다 보는애, 위조인지 아닌지)는 (5)와 같이 UserDetailsService(신분증 보는 기준)를 이용해 UserDetails(인적 사항)을 조회한다.
- UserDetailsService는 (5)에서 보듯이 데이터베이스 등의 저장소에서 사용자의 크리덴셜(비밀번호)를 포함한 정보 조회
- 데이터베이스에서 조회한 정보를 기반으로 (7)과 같이 UserDetails를 생성 후, 이를 AuthenticationManager에게 전달한다.
- UserDetails를 전달받은 AuthenticationManager는 PasswordEncoder 를 이용해 UserDetails 안의 암호화된 비밀번호와 Authentication 안의 비밀번호가 일치하는지 검증(9)
- AuthenticationProvider는 인증된 Authentication(신분증, 이거 정상임 이라고 이제 찍어놓음)을 ProviderManager에게 패스(10)
- ProviderManager는 (11)과 같이 인증된 Authentication(신분증)을 다시 UsernamePasswordAuthenticationFilter에게 패스
- 인증된 Authentication(신분증)을 전달받은 UsernamePasswordAuthenticationFilter는 (12)와 같이 SecurityContextHolder(인증 된 것 저장)을 이용해 SecurityContext(인증된 신분증 저장고)에 인증된 Authentication(신분증)을 저장한다.
뭔 단계가 많고 이름이 길고 복잡하냐 할 수 있는데,
사실 단순히 보면
술집 갈 때 신분증을 냄
-> 카운터에(UsernamePasswordAuthenticationFilter) 제출
->신분증 검증 업무 시작 (UsernamePasswordAuthenticationToken)
->신분증을 매니저 (ProviderManager) 가 받아서
->이게 진짜인지 아닌지 감별하는 애(AuthenticationManager) 가 봄, UserDetails(인적 사항)등등조회
-> 정상임
-> 다시 ProviderManager 에게 줌
-> ProviderManager 는 카운터에 가서 얘 진짜 신분증 맞아요 라고 함
-> 카운터에 있는 사람 (SecurityContextHolder)은 ㅇㅋ 하고 신분증 낸 사람을 기억함 (SecurityContext)
끝
핵심은 인증하는 과정에서 (3)번의 신분증은 아직 검사를 받지 않은 신분증이니까 인증이 안된 신분증이고,
(8)번의 신분증은 검사 받고 이거 정상임 한 신분증이다.
다른 예로 여권 출국할때 도장을 찍는데
내가 제출할 때 -> ㅇㅋ 도장 안찍혀 있음
여권 돌려받을때 -> ㅇㅋ 도장 찍혀 있음
이 차이라고 생각하자
4.Spring Security의 권한 부여 처리 흐름
앞에서 신분증 검사를 했다.
통과 했다면 일단 문제는 없다 이거다.
통과 하면 이제 막 어디든 들쑤시고 다니면되나?
아니다. 내가 vip인지 그냥 일반 손님인지 점장인지 권한이 주어진다.
Spring Security의 컴포턴트 관점에서의 권한 부여 처리(Authorization) 흐름
AuthorizationFilter는 권한부여 Filter로 Spring Security Filter Chain에서 URL을 통해 사용자의 엑세스를 제한하는 역할을 한다.
- AuthorizationFilter는 먼저 (1)과 같이 SecurityContextHolder(카운터)에서 Authentication(신분증)을 받는다.
- (2)와 같이 받은 Authentication(신분증)을 HttpServletRequest(확인 요청서 라고 하자) 와 함께 AuthorizationManager(매니저)에게 전달한다.
- AuthorizationManager는 권한 부여 처리를 총괄하는 매니저 역할을 하는 인터페이스이고, RequestMatcherDelegatingAuthorizationManager는 AuthorizationManager를 구현한 구현체이다.
(AuthorizationManager(매니저)의 일을 RequestMatcherDelegatingAuthorizationManager(알바) 가 한다) - RequestMatcherDelegatingAuthorizationManager 내부에서 매치되는 AuthorizationManager구현 클래스가 있다면 AuthorizationManager구현 클래스가 사용자의 권한을 체크한다. (3)
-> 아르바이트생 중 신분증 특히 잘 보는 애 있으면 걔 갖다준다. - 적절한 권한이라면 (4)와 같이 프로세스 진행
- (5)와 같이 적절한 권한이 아닌 경우 AccessDeniedException(이분 못들어 오시는데)이 throw(를 보고하고) 되고 ExceptionTranslationFilter(경비 담당 아르바이트가)가 AccessDeniedException(여기 들어오시면 안되요)을 처리하게 된다.
이것도
카운터에서 매니저가 신분증 가져감
-> 신분증 아르바이트생이 받아서 이분 vip인데요, 혹은 일반 손님 인데요 를 함
-> 권한 있는 사람이면 통과, 아니면 여기 들어가시면 안되요 함
라고 생각하자
이번 세션에서는 초반에 내용이 많고, 후에는 적어서 그나마 블로깅 하면서 공부 할 수 잇어'ㅅ다;ㅣ.
코드 실습이 많았는데, 뒤에는 흐름파악이 주류라서 다행이었다.
흐름 부분은 거의 강의 자료랑 똑같은데 최대한 좀 더 이해 되게 예시를 들어 썻는데 이게 더 이해가 잘 되는지는 모르겟다 ㅋㅋ
'백엔드 > 코드스테이츠 수강' 카테고리의 다른 글
[회고]코드스테이츠 수강_수료 후기 -1편- (4) | 2023.05.29 |
---|---|
[회고]코드스테이츠 수강_20주차_3일차_부스트캠프 4달 경과 (6) | 2022.12.14 |
코드스테이츠 수강_15주차_4일차_인증, 보안 기초 (1) | 2022.11.17 |
[회고]코드스테이츠 수강_15주차_3일차 부스트캠프 3달 경과 (1) | 2022.11.16 |
코드스테이츠 수강_11주차_3일차~_12주차_1일차 Spring Data JDBC , DDD (0) | 2022.11.02 |