참고한 영상들
등장배경
HTTP 의 stateless
한 특성때문에 서버는 각 요청이 기존의 클라이언트로부터 온 것인지, 새로운 클라이언트로 온 것인지 알 수 없다. HTTP의 요청은 독립적으로 소켓 1개를 사용하고 다른 요청과 독립적이기 때문이다.
즉, 서버는 로그인(인증)을 해도 그 이후에 요청에서 사용자가 이전에 로그인을 한 상태인지 알 수 없는 것이다.
모든 HTTP 요청에 사용자의 아이디와 패스워드를 담아 로그인을 반복하는 것은 보안에 취약하고 서버에 부하를 준다. 이 문제를 해결하기 위해서 웹 서버는 쿠키와 세션ID를 사용해 클라이언트를 구분한다.
세션과 쿠키
세션과 쿠키를 이용한 클라이언트 구분 과정
-
사용자가 로그인을 한다. 사용자가 아이디와 비밀번호를 HTTP 요청 메시지에 담아 서버로 보내면 서버는 DB의 데이터와 사용자의 데이터를 대조하여 인증을 완료한다.
-
세션DB에 세션 ID가 저장된다. 사용자의 인증이 완료되고 세션 DB에 세션 ID가 저장된다. 이 세션 ID를 HTTP 응답 메세지의 쿠키에 담아 브라우저에 저장한다.
-
사용자가 다른 서비스에 대한 요청을 보낸다. 브라우저에 저장된 쿠키가 HTTP 요청 메시지에 같이 담겨 보내진다. 서버는 쿠키에 담긴 세션 ID가 세션 DB에 있는지 확인한다. 세션 DB에 세션 ID가 있다는 것이 확인되면 이 세션 ID를 가진 사용자가 세션 상태라는 것을 인정한다.
이 과정을 통해 서버는 클라이언트의 세션 상태를 구분할 수 있다. 또한, 사용자의 세션을 추적해 제어할 수 있다. 예를 들어, 다른 기기에서 로그인 한 세션을 종료시키거나 넷플릭스와 같은 ott서비스에서 동시접속수를 관리하는 등의 일이 가능하다.
하지만 이 방법에도 단점이 있다.
- 쿠키는 보안이 취약해 해커들에게 탈취될 가능성이 있다. 그렇게 때문에 쿠키에는 노출되어도 상관없는 데이터를 담는다. 예를 들어, 장바구니 정보나 일주일동안 보지않기와 같은 정보를 담을 수 있다. 또한, 공격을 방지하기 위해 HTTPS를 필수적으로 사용해야한다.
- 매 요청마다 세션DB와 세션ID를 대조해야하기 때문에 서버에 부하가 생긴다. 보통은 REDIS와 같은 캐시 서비스를 함께 사용해 서버의 부하를 줄인다.
- 로드밸런스 서비스를 이용하면 쿠키나 세션 정보가 사라질 수 있다. 로드밸런스 서비스를 이용하면 사용자가 처음 접속한 서버와 다른 요청을 위해 접속한 서버가 달라질 수 있다. 이 때, 접속 서버가 달라지면서 쿠키나 세션 정보가 사라질 수 있다. 이전 요청에 대한 쿠키를 저장한 서버와 새로 접속한 서버가 달라지기 때문이다. 이를 보완하기 위해 스티키세션이라는 기능을 사용하기도 한다.
이러한 단점을 보완하기 위해서 등장한 것이 JWT(Json Web Token)
이다.
JWT
jwt는 헤더
, 페이로드
, 서명
의 세 부분으로 이루어진다. 헤더에는 토큰의 타입(jwt)과 알고리즘에 대한 정보가 담긴다. 페이로드에는 사용자에 대한 데이터를 담은 클레임이 담긴다. 헤더와 페이로드에 서버의 비밀키를 조합해 만든 암호가 서명에 담긴다. 서버는 이 서명을 이용해 토큰이 유효한 지 알 수 있다.
JWT를 이용한 클라이언트 구분 과정
-
사용자가 로그인을 한다. 사용자가 아이디와 비밀번호를 HTTP 요청 메시지에 담아 서버로 보내면 서버는 DB의 데이터와 사용자의 데이터를 대조하여 인증을 완료한다.
-
HTTP 응답 메시지의 헤더에 jwt를 담아 보낸다.
-
사용자가 다른 서비스에 대한 요청을 보낸다. HTTP 요청 메시지의 헤더에 jwt를 함께 담아 보낸다. 서버는 이 토큰이 유효한지 확인한 후 사용자임을 확인한다.
세션이 서버에 저장되어 일일히 관리되고 제어할 수 있다면 jwt는 사용자가 토큰을 갖고 있기때문에 토큰을 임의로 만료시키는 등 제어가 불가능하다. 예를 들어, jwt가 탈취되어 악용되어도 이 jwt를 강제로 만료시킬 수가 없다.
이러한 문제를 해결하기 위해 엑세스 토큰
과 리프레쉬 토큰
을 함께 발급해 사용한다.
엑세스 토큰과 리프레쉬 토큰
리프레쉬 토큰은 비교적 긴 시간 (2주 정도) 이후에 만료되는 토큰이다. 최초 로그인 시 서버 DB에 저장을 한다. 리프레쉬 토큰을 이용해 엑세스 토큰을 발급한다. 엑세스 토큰은 비교적 짧은 시간 (3시간 정도) 이후에 만료되는 토큰이다. 이 토큰이 만료되면 사용자는 서버에 있는 리프레쉬토큰을 이용해 엑세스 토큰을 다시 발급받아 사용할 수 있다.
마치며
세션이나 쿠키, 토큰은 웹에 대한 기본적인 지식이지만 의외로 정확하게 알지 못하는 사람이 많을 것이라는 예상이 든다. 실제로 사용할 때 이에 대한 개념이 명확하지 않으면 계속 헷갈리기 때문에 초장에 잘 알아두는 편이 좋을 것 같다! 쿠키는 이전에 어뷰징을 막기위해 사용한 적이 있는데 이에 대한 포스팅도 나중에 작성해야겠다.
AWS Cognito도 jwt를 이용해서 인증을 진행한다.