스프링

스프링 시큐리티 내부 흐름

백수왕 2023. 12. 18. 02:29

흐름을 보기 전에 서블릿과 필터를 알아보자

1. 서블릿

JAVA 애플리케이션은 요청을 받은 후 그것을 HTTP 프로토콜로 전송한다. 브라우저들은 HTTP 프로토콜만 이해할 수 있기 때문이다.

따라서 HTTP 프로토콜을 이용해서 브라우저들은 백엔드 웹 애플리케이션에 요청을 보낼 수 있다.

JAVA 애플리케이션은 HTTP 프로토콜을 이해할 수 없기 때문에 JAVA 코드와 브라우저 사이에 중개자가 존재하는데 이 중개자를 서블릿 컨테이너 or 웹 서버라고 합니다.

중재자 즉, 서블릿 컨테이너가 할 일은 브라우저로 부터 받은 HTTP 메시지를 ServletRequest object 로 변환합니다.

그리고 동일한 object를 웹 애플리케이션에 사용하고 있는 JAVA 코드 프레임워크에도 주어집니다.

브라우저에 다시 요청을 보내려 할 때 서블릿은 HTTP ServletResponse object를 가져다가 브라우저가 이해할 수 있는 HTTP 메시지로 변환합니다.

이러한 모든 일은 서블릿이라는 컨셉 때문에 생겼는데, 서블릿은 웹 애플리케이션에서 중요한 역할을 하지만 복잡한 성격 때문에 직접 사용하는 일은 드뭅니다.

따라서 이 일을 쉽게 하기 위해 spring프레임워크와 springboot가 생겼습니다.

우리가 원하는 REST 서비스, MVC Paths와 웹 페이지를 지정하면 내부적으로 Spring boot 와 Spring 프레임워크가 서블릿을 생성합니다. 그리고 서블릿 관련된 복잡한 로직 또한 담당하여 처리합니다.

2. 필터

웹 애플리케이션을 향해 들어오는 모든 요청을 가로챌 수 있다. 

이러한 필터는 실질적인 비즈니스 로직이 실행되기 전에 일어났으면 하는 처리를 수행할 수 있다.

ex) 사용자의 요청이 특정 리소스에 접근하려고 할 때, 그 요청이 유효한지를 먼저 확인하거나, 사용자가 해당 리소스에 대한 권한을 가지고 있는지를 검사한다.

스프링 시큐리티 내부 흐름

1. Spring Security Filters 

백엔드 서버에 들어오는 모든 요청을 감시한다. 유저가 접근하고자 하는 경로를 확인한다. 

이것이 보호된 자원인지 공개적으로 접근 가능한 자원인지를 판별하고 이에 따라서 유저에게 인증을 강제해야 할지 아닐지 결정한다.

그 결과에 따라 로그인 페이지를 표시하고 유저가 보안 웹페이지에 접근하는 첫 번째 시도에 발생한다.

인증에 성공하면 유저가 로그인 했는지 안 했는지 체크하는 로직도 갖추는데 그에 따라 필터는 로그인 페이지를 강제하지 않는다.

유저가 보내는 유저네임과 비밀번호를 추출하고 2단계(Authentication) 안의 인증객체로 변환한다. 

2. Authentication 

Spring Security 유저의 정보를 저장하기 위한 핵심 표준. 

유저네임과 자격 증명만을 보유함. 이 인증 객체가 형성되면 필터가 3단계(Authentication Manager)에게 넘긴다. 

3. Authentication Manager 

실질적인 인증 로직을 관리하는 관리 인터페이스 or 클래스이다. 웹 애플리케이션 안에 어떤 인증 제공자(Authentication Providers)가 존재하는지 확인한다. 특정 요청에 대해 유효한 인증 제공자가 어떤 것인지 확인하는 것. 

4. Authentication Providers 

1개 or N개의 인증 제공자를 정의할 수 있다면 이 인증 제공자들 내부에 실질적인 인증 로직을 정의할 수 있다.

ex) 어떤 데이터베이스나 LDAP 서버 or 권한 부여 서버나 캐시에서 유저 자격 증명을 확인할 것인지.

Authentication Providers에서 또 다수의 인증 제공자를 작성할 수 있다. 역할을 분담하는 것.

5. UserDetails Manager/Service 

인증 제공자 안에서 실질적인 인증 로직을 직접 작성하거나 UserDetails Manager/Service라는 인터페이스와 클래스를 활용할 수 있는데, 어떤 인증을 수행하고자 할 때 DB같은 저장소나 LDAP로부터 유저 정보를 불러오는 것이기 때문이다. 

이 유저 정보를 불러오고 유저가 제공한 정보와 저장소 안에 저장된 정보를 비교할 수 있다.

거의 대부분 프로젝트에서 필요한 요구사항인데 이 Spring Security는 인터페이스로 이미 제공한다.

인증 제공자안에 원한다면 직접 작성할 수 있다.

6. Password Encoder

인증서 내부에는 비밀번호가 있는데 그냥 저장하면 보안에 취약해진다.

그래서 비밀번호를 저장소에 저장하거나 유저가 제공한 비밀번호를 불러와서 확인하고자 할 때 항상 암호화 또는 해싱해야 한다.

이 모든 비밀번호 관련 표준과 로직을 수행하기 위해 PasswordEncoder 인터페이스와 그 구현체가 있다.

7. Authentication Manager

요청이 들어오면 해당 인증 관리자에게 전송하는데

만약 실패할 경우 바로 실패를 반환하는 것이 아니라 모든 인증 제공자에게 요청을 해서 모두 실패할 경우 그제서야 실패를 반환한다. 

8. 

4, 5, 6 과정이 끝나면 다시 인증 관리자에게 넘어오는데 이 정보는 필터로 돌아간다.

9. Security Context

유저에게 응답을 보내기 전에 필터들은 2단계에서 이들이 생성한 인증 객체를 보안 컨텍스트 안에 저장하려고 한다.

여기서 저장되는 인증 객체는 인증이 성공적이었는지 아닌지와 세션ID를 갖게된다.

이런 정보를 9단계에서 갖고있기 때문에 인증이 성공적이었다면 두 번째 요청부터는 해당 유저의 자격 증명을 요구하지 않는다.

10.

위 과정이 다 통과된다면 유저에게 권한이 넘어간다.