시큐리티에서의 세션은 굉장히 중요한 역할을 한다. 클라이언트와의 연결 관계에서도 아주 큰 역할을 하고 우리 서비스의 사용자와의 얘기에도 엄청나게 큰 역할을 한다. 그렇다면 세션이라는것은 시큐리티에서 가장 신경을 많이 쓰고 까다롭게 생성하고 사용되어야 한다는 말이다. 그렇다면 시큐리티의 세션을 담당하는 필터는 무엇이며 해당 필터는 어떤 일을 하는지 알아보자
SessionManagementFilter
- 세션 관리
- 당연하게도 인증시 사용자의 세션 정보를 등록하고 조회, 삭제등의 다양한 세션의 이력을 관리한다.
- 동시적 세션 제어
- 동일 계정으로 접속이 허용되는 최대 세션수를 제한한다
- 세션 고정 보호
- 인증 할 때마다 세션 쿠키를 새로 발급하여 공격자의 쿠키 조작을 방지한다
- 세션 생성 정책
- Always, If_Required, Never, Stateless
우리는 이중 동시적 세션 제어, 세션 고정 보호, 세션 생성 정책을 나누어 알아보도록 하자
동시적 세션 제어
동시에 세션을 관리하는 시큐리티 설정은 어떻게 하는것일까?
사진을 보면 동시 접근 제어를 관리하는 sessionManagement 를 만들어 주었다.
- invalidSessionUrl은 세션이 유효하지 않을때 이동 할 페이지를 지정한다
- maximumSessions는 최대 허용 가능한 세션의 수이다. 참고로 -1 이라고 적는다면 무한으로 로그인 세션을 허용한다.
- expiredUrl은 만약 해당 세션이 만료되었다면 이동할 페이지를 지정해주는것이다.
- maxSessionPreventsLogin(true)은 true 가 기존의 사용자 세션을 유지하고 false가 기존 세션을 만료 시키는것이다.
우선 재밌는 상상을 한번 해보자
우리는 개발자로써 로그인 기능을 맡았다 근데 누군가가 로그인기능에 같은 아이디는 동시 접속을 불가능하게 하고 싶다고 말을 한것이다. 그래서 우리는 동시 접속 제어를 하기로 마음을 먹었다 물론 시큐리티를 사용해서 말이다.
그렇다면 시큐리티를 이용하는 방법 중 동시에 같은 아이디에 세션값을 받아 사용하는것을 막는 방법이 무엇이 있을까
- 현재 로그인하는 사람을 막는 방법
- 조금만 생각해보면 간단하다. 이전의 사용자에게 주었던 세션 값은 서버에도 저장되어있을것이다. 그렇다면 그값을 비교하여 맞지 않다면 예외처리를 통해 로그인을 불가능 하게 만들면 된다.
- 이전 사용자를 로그아웃 시키는 방법
- 이것이 조금 생각해볼 필요가 있는데 그렇다고 막 엄청 어렵진 않을것이다. 조금만 바꿔서 생각해보자.
이전 사용자의 인증도구를 못사용하게 만든다. 그리고 해당 인증 객체에게 새로운 세션을 만들고 저장해준다.
그렇다면 인증 도구를 사용하지 못하게 하는 방법은 무엇일까? 바로 인증 도구인 세션을 만료시키는 것이다. - 그렇다면 만료시키는 방법이 무엇일까?? 이는 SessionManagementFilter와 밀접한 관련이 있는 CuncurrentSessionFilter 에서 알아볼수있지만 짧게 말해보자면 동시 접근 세션 갯수를 확인하는 클래스를 갔다가 세션을 변경시키는 클래스를 지나쳐 세션의 카운트를 올려주는 클래스까지 가서 변경을 완료하고 기존의 사용자를 로그아웃 시키는 방법이다.
너무 뭉뚱그려서 설명했으니 꼭 CuncurrentSessionFilter를 보고 오길 바란다.
- 이것이 조금 생각해볼 필요가 있는데 그렇다고 막 엄청 어렵진 않을것이다. 조금만 바꿔서 생각해보자.
세션 고정 제어
세션 고정은 무엇일까? 말그대로다 세션을 고정되어있다는것이다. 애초에 처음 발급받은 세션이 고정값이라는 것이다. 이는 csrf 공격에 매우 취약하며 꼭 뭔가 조취를 취해야하는것이다. 위에 CuncurrentSessionFilter 에 대한 글을 보고 왔다면 갑자기 떠오르는 것이 있을것이다. 바로 ChangeSessionIdAuthenticationStrategy 이다.
딱 보면 바로 눈이 가지 않는가? 해당 메소드를 통해 세션을 고칠것이다. 여긴 여러가지의 변환 방법이 있는데
- changeSessionId() 이것이 서블릿 3.1 윗 버전의 기본값이다. 사용자가 인증을 시도하면 해당 세션은 그대로 둔 상태에서 ID만 바뀐다.
- migrateSession() 이것은 서블릿 3.1 아랫버전의 기본값이다. 사용자가 인증을 시도하면 세션과 세션 ID 두개다 변경한다.
- newSession() 세션과 세션ID 모두 새롭게 발급하지만 이전의 설정을 모두 초기화한다
- none 이것은 아무것도 하지않겠다 즉, 해당 세션값을 고정하겠다 라는뜻 ( 공격해봐라 라는 뜻이다 )
세션 정책
만약 다른분들이 만든 시큐리티를 따라 치거나 혹은 본적이 있다면 정책을 알것이다.분명히 알고있을것이다.
익숙하지 않은가?? 우선 현재 정택은 Stateless 정책을 사용하고 있다. 4가지의 정책이 있다
- SessionCreationPolicy.Always : 스프링 시큐리티가 항상 세션을 생성한다
- SessionCreationPolicy.If_Required : 스프링 시큐리티가 필요 시 생성( 기본값 )
- SessionCreationPolicy.Never : 스프링 시큐리티가 생성하지는 않지만 이미 존재하면 사용한다
- SessionCreationPolicy.Stateless : 스프링 시큐리티가 생성하지 않고 존재해도 사용하지 않는다.
우리가 다른 사람들이 만든 값을 보면 대부분 Stateless 값으로 설정을 해놓는것을 볼수 있다. 이는 Session값을 사용하지 않고 JWT 토큰을 이용해서 만든 분들이 대부분 설정하는 값인데 이 글을 본사람들은 왜 Stateless 라고 적는지 그리고 내가 세션값을 사용하는 일이 생길수 있다 라면 당당하게 고를수 있는 사람이 되었으면 좋겠다! 나도
정리
SessionMenagementFilter에서 해주는 다양한 일들은 굉장히 중요한 일이고 이를 해결할 수 있어야 우리가 시큐리티를 공부했다라고 생각할수 있다. 세션에 대한 다양한 정책을 통해 로그인 기능을 좀 더 넓혀서 생각해볼수 있는것이다. 우리가 로그인 기능을 만들면 한번쯤 꼭 부딫힐만한 일이 된다. 이중 로그인이 왜 되는거지?? 어떻게 하면 방지 할수 있을까? 세션값이 계속 고정된 상태로 클라이언트에게 전송되는데 시큐리티가 주는 csrf토큰 값말고도 세션값 자체를 바꿔서 방지를 더할수 없을까?? 같은 다양한 생각은 우리가 아닌 많은 사람들이 하는 생각이다. 그렇다는건 스프링은 이미 우리를 위해 준비해 놓은 값이 있는 것이다. 우리가 뭔가 막혀 답답할때는 스프링을 한번 천천히 훑어보자 왠만한 정답은 이미 만들어져있다.
JWT 토큰으로 도입 해보자!
이것을 JWT 토큰으로 인증 방식을 개선하면서 똑같이 구현하기로는 정말 어렵다. 그래서 내가 이해한 JWT 토큰은 이 방식을 활용한다.
- 동시적 접근 제어 : refreshToken을 DB에 직접 저장하면서 동시 접근을 제어해 보는것이다.
- 이전 사용자 로그아웃 : 새로운 로그인을 진행하면 토큰을 새로 발급해서 해당 사용자의 refreshToken값을 새로 저장한다. 그리고 이전 사용자의 refreshToken을 검증하는 로직을 생성하여 아니면 예외처리를 통해 로그아웃시키면 되고
- 해당 사용자 로그인 불가능 : 이전 사용자의 로그인이 깨지지 않게 하려면 한번 발급된 리프레쉬토큰은 현재 사용자가 아니면 재발급 받을수 없다. 그러면 그 값과 비교하여 로그인 불가 처리를 진행하면 된다. 없다면 로그인이 된것이 아니니까
- 세션 고정 제어 : 이는 JWT 토큰의 단점 중 하나인데 refreshToken또한 저장된 토큰으로써 세션과 다를것이 무엇이냐 라고 하지만 이건 재발급을 통해 방지를 할수 있다 refreshToken을 다루는 서비스라면 accessToken을 발급하는것이 당연한데 refreshToken은 기본적으로 유효기간을 길게 갖는다 하지만 그에 반해 accessToken은 유효기간이 정말 짧다. 그래서 changesessionId처럼 accessToken을 새로 발급 받을때마다 refreshToken을 새로 발급한다. 그러면 완벽하게 똑같진 않지만 언뜻 닮은 행위를 진행하는것이다
- 세션 정책 : JWT 토큰을 사용한다는것은 인증 도구를 아예 바꾸겠다는 말이다 즉, Stateless하게 만든다는 것이다.
'Spring > 👨💻 SpringSecurity' 카테고리의 다른 글
AnonymousAuthenticationFilter (0) | 2023.06.26 |
---|---|
RememberMeAuthenticationFilter (0) | 2023.06.26 |
CuncurrentSesseionFilter (0) | 2023.06.26 |
Logout (0) | 2023.06.26 |
CSRF (0) | 2023.06.26 |