티스토리 뷰

Spring

Spring security 정리

kingsubin 2021. 2. 2. 12:06

Spring security 사용하는게 어려워서 글 여러 개 읽고 복습겸 나중에 읽기 쉽게 할려고 적는 글이다.

자세한 내용은 잘 정리된 블로그 글 들이 많으니 그걸 보는게 더 좋을것 같다.

 

※ 출처 및 참초 게시글 모음

kingsubin.tistory.com/349


보안관련 용어

인증 (Authentication)

- 보호된 리소스에 접근한 대상이 누구인지 확인 하는 과정 

 

인가 (Authorization)

- 인증된 사용자가 요청한 리소스에 접근 가능한지를 결정하는 과정

 

접근 주체 (Principal)

- 보호된 리소스에 접근하는 대상

 

비밀번호 (Credential)

- Resource에 접근하는 대상의 비밀번호

 


세션 기반 인증과 토큰 기반 인증

세션 기반 인증

- 클라이언트 측에서 서버에 로그인 요청

- 처음 Request 에는 세션 정보가 없기에 서버에서 session id 를 발급해준다.

- 다음부터 클라이언트는 요청의 header 정보에 session id 를 담아서 요청한다.

- 서버측에서는 이미 session id 를 알기에 추가 발급할 필요가 없다.

- 서버측에서는 header 에 담긴 session id 를 기반으로 사용자를 식별한다.

 

https://brunch.co.kr/@springboot/491
https://brunch.co.kr/@springboot/491

서비스 사용자가 급증하여 트래픽 증가시 서버 1대로 운영하기에는 부담이 커 서버를 증설하였다고 가정하자.

- 위와 같이 트래픽을 분산하여 두 대의 서버에 호출하게되면 각각의 웹 서버에서는 관리하는 세션 정보를 서로 공유하고 있지 않다.

- 즉, 세션 정보가 일치하지 않는다.

 

해결책으로는 세션을 공유할 수 있는 별도의 세션 저장소를 구축하면 된다.

https://brunch.co.kr/@springboot/491

- Redis 라는 별도의 세션 저장소를 사용하면 해결할 수 있다, (Monogo DB 또는 다른 저장소도 사용 가능)

 

만약 세션을 활용하여 인증을 구현한다면 세션 저장소와 웹 서버를 따로 분리해야 좋겠다.

웹 서버만 확장해야 하는 경우도 있을 수 있고 세션 저장소만 확장해야 하는 경우도 있을 것인데 서로 강하게 의존성을 맺고있다면 

효율적인 서비스 확장이 불가능하다.

 


토큰 기반 인증

- 인증 받은 사용자들에게 토큰을 발급

- 서버에 요청 할 때 헤더에 토큰을 함께 보내도록 유효성 검사

- 서버나 세션에 유지하지 않고 클라이언트 측에서 들어오는 요청만으로 작업을 처리

- 상태를 유지하지 않으므로 Stateless 한 구조를 가진다.

- Stateless 한 구조를 가지니 서버 확장에 유리하다.

- 최근에는 JSON 포맷을 이용하는 JWT (JSON Web Token) 을 사용한다.

 

https://brunch.co.kr/@springboot/491

- 클라이언트 측에서 서버에 로그인 요청

- 정보 검증 후 사용자에게 Signed 토큰을 발급 (Signed는 해당 토큰이 서버에서 정상적으로 발급된 토큰임을 증명하는 Signature를 가지고 있다는 뜻)

- 클라이언트 측에서 전달받은 토큰을 저장해두고, 서버에 요청할 때마다 토큰을 header 에 담아 함께 전달

- 서버측에서는 header 에 담긴 토큰을 기반으로 사용자 식별

 


JWT (Json Web Token)

- JSON 객체를 통해 안전하게 정보를 전송할 수 있는 웹 표준 (RFC7519) 

- JSON 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token

- 토큰 자체를 정보로 사용하는 Self-Contained 방식으로 정보를 전달

- JWT 는 ' . ' 을 구분자로 세 부분으로 구분되어 있는 문자열

- 각각 헤더는 토큰 타입과 해싱 알고리즘, 내용은 실제 전달할 정보, 서명에는 위변조를 방지하기 위한 값이 들어가 있음

https://mangkyu.tistory.com/56

 

JWT 구조 

- Headeer, Payload, Signature 세 부분으로 이루어져 있음

- 각 부분은 Base64로 인코딩 되어 표현

- 각각의 부분을 이어주기 위해 '.' 구분자를 사용

- 암호화된 문자열이 아니기에 같은 문자열에 대해 항상 같은 인코딩 문자열을 반환

 

https://webfirewood.tistory.com/115
https://mangkyu.tistory.com/56

 

자세한 내용은 이 블로그 게시글이 정리가 잘 되어있음

나중에 필요할때 다시 보기

mangkyu.tistory.com/56


Spring Security 

- Spring Security 에서는 Principal을 id로, Credential을 password로 하는 Credential 기반의 인증 방식을 사용한다.

- Spring 기반의 애플리케이션의 보안을 담당하는 스프링 하위 프레임워크

- 보안과 관련해 체계적으로 많은 옵션을 제공해주기에 일일이 보안관련 로직을 작성하지 않아도 된다.

 

 

Form 로그인 기반 과정

1. 사용자가 로그인 정보와 함께 인증 요청 (Http Request)

2. AuthenticationFilter (구현체 UsernamePasswordAuthenticationFilter) 가 HttpServletRequest 에서 사용자가 보낸 name, password 를 인터셉트, 인증용 객체 UsernamePasswordAuthenticationToken 을 만들어서 넘겨줌.

3. AuthenticationManager (구현체 ProviderManager) 에게 UsernamePasswordAUthenticationToekn 전달

4. 실제 인증을 처리하는 AuthenticationProvider 에게 UsernamePasswordAUthenticationToekn 전달

5. DB에서 사용자 인증 정보를 가져올 UserDetailsService 객체에게 사용자 아이디를 전달

6. DB에서 인증에 사용할 사용자 정보(사용자 아이디, 암호화된 패스워드, 권한 등)를 UserDetails(인증용 객체와 도메인 객체를 분리하지 않기 위해서 실제 사용되는 도메인 객체에 UserDetails를 상속하기도 한다) 라는 객체로 전달 받음

7. AuthenticationProviderUserDetails 를 받아 사용자 정보와 비교
8. 
DB의 비밀번호와 매칭되는 경우 인증이 성공된 UsernameAuthenticationToken을 생성하여 AuthenticaionManager로 반환함

9. AuthenticaionManagerUsernameAuthenticaionTokenAuthenticaionFilter로 전달함

10. AuthenticationFilter는 전달받은 UsernameAuthenticationTokenLoginSuccessHandler로 전송하고, SecurityContextHolder에 저장

 


Spring Security Filter

https://webfirewood.tistory.com/115#comment12286684

 

스프링 시큐리티는 다양한 필터체인을  사용하여 커스터마이징을 할 수 있도록 도와준다.

가볍게 읽어서 구조만 파악하고 나중에 필요할때 찾아서 쓰자.

 

 

  • SecurityContextPersistentFilter : SecurityContextRepository에서 SecurityContext를 가져와서 SecurityContextHolder에 주입하거나 반대로 저장하는 역할을 합니다.
  • LogoutFilter : logout 요청을 감시하며, 요청시 인증 주체(Principal)를 로그아웃 시킵니다.
  • UsernamePasswordAuthenticationFilter : (아이디와 비밀번호를 사용하는 form 기반 인증) 설정된 로그인 URL로 오는 요청을 감시하며, 유저 인증 처리
    • AuthenticationManager를 통한 인증 실행
    • 인증 성공 시, 얻은 Authentication 객체를 SecurityContext에 저장 후 AuthenticationSuccessHandler 실행
    • 인증 실패 시, AuthenticationFailureHandler 실행
  • DefaultLoginPageGenerationFilter : 사용자가 별도의 로그인 페이지를 구현하지 않은 경우, 스프링에서 기본적으로 설정한 로그인 페이지로 넘어가게 합니다.
  • BasicAuthenticationFilter : HTTP 요청의 (BASIC)인증 헤더를 처리하여 결과를 SecurityContextHolder에 저장합니다.
  • RememberMeAuthenticationFilter : SecurityContext에 인증(Authentication) 객체가 있는지 확인하고 RememberMeServices를 구현한 객체 요청이 있을 경우, RememberMe를 인증 토큰으로 컨텍스트에 주입합니다.
  • SecurityContextHolderAwareRequestFilter : HttpServletRequestWrapper를 상속한 SecurityContextHolderAwareRequestWapper 클래스로 HttpServletRequest 정보를 감싼다. SecurityContextHolderAwareRequestWrapper 클래스는 필터 체인상의 다음 필터들에게 부가정보를 제공한다.
  • AnonymousAuthenticationFilter : 이 필터가 호출되는 시점까지 사용자 정보가 인증되지 않았다면 익명 사용자로 취급합니다.
  • SessionManagementFilter : 요청이 시작된 이후 인증된 사용자인지 확인하고, 인증된 사용자일 경우 SessionAuthenticationStrategy를 호출하여 세션 고정 보호 매커니즘을 활성화 하거나 여러 동시 로그인을 확인하는 것과 같은 세션 관련 활동을 수행합니다.
  • ExceptionTranslationFilter : 필터체인 내에서 발생되는 모든 예외를 처리합니다.
  • FilterSecurityInterceptor : AccessDecisionManager로 권한부여처리를 위임하고 HTTP 리소스의 보안 처리를 수행합니다.