JWT란?
JWT는 어디 사용되고, 어떻게 사용되는가?
하지만 JWT를 알아보기 전에 우선 세션부터 알아보자.
웹 사이트의 여러 페이지에 걸쳐 사용되는 사용자 정보를 저장하는 방법 중 하나로 웹 서버가 세션 아이디 파일을 만들어 서비스가 돌아가고 있는 서버에 저장을 하는 것을 말한다.
유저가 웹 브라우저를 켜고 www.naver.com을 입력했다고 하자. (GET 방식)
서버는 해당 주소에 맞는 컨트롤러의 메서드를 찾는다. 그리고 그 메서드에서 메인 페이지에 맞는 html 파일을 리턴해준다.
이때 http 헤더에 어떤 것을 달고 보낸다. 뭘 달아서 보내나?
바로 쿠키를 담아서 보내는데 이 쿠키에 세션 ID를 생성해서 담아 보낸다.
(여기서 세션ID의 예시로 1234라고 하겠다.)
웹 브라우저는 이 세션 ID를 받아서 자동으로 쿠키라는 저장 영역에 세션 ID(1234)를 담는다.
이것이 언제 만들어지느냐? 바로 최초 요청시 만들어진다.
두번째 요청부터는 헤더에 세션 ID(1234)를 달고 간다. (첫 요청처럼 서버에서 세션 ID를 새로 생성하는 것이 아니라 기존 것 1234를 서버가 그대로 돌려주는 것)
예를 들어보자면 기억력이 좋지 못한 친구집에 놀러갔다고 하자. 그 친구는 상대가 집에 방문한적이 있는지 없는지 구분하기 위해 카드를 나눠줘서 기억을 하는 친구이다. 내가 그 친구집에 첫 방문을 하면 “너 우리집에 처음왔지? 이 카드 받아”하고 처음 방문한 사람에게 나눠주는 카드를 준다. 두번째 방문할 때에 이 카드를 들고가지 않으면 친구가 “너 우리집에 처음온거야?”하고 물어볼 것이다. 그 친구는 카드가 없으면 이전에 방문했던 것은 기억을 하지 못하는 친구이기 때문에 재방문인지 구분을 위해 방문 카드가 필요한 것이다.
재방문 때 카드를 보여주면 그 친구는 내가 저번에 방문 했었구나하고 알 수 있다.
여기서 이 기억력이 나쁜 친구가 바로 '서버'이고 방문 카드가 바로 '세션', 그리고 카드에 적힌 번호가 '세션 ID'이다. 서버는 방문 카드를 들고가지 않으면 처음 방문한건지, 재방문인지 구분을 하지 못한다. 그래서 서버는 처음 방문할 때 무조건 카드를 발급해준다. 그리고 재방문시 카드를 들고오면 재방문이라는 것을 인식한다.
그렇다면 한번도 방문한적 없는 친구가 카드를 위조해서 들고가면 서버는 구분하지 못하겠지?
이것을 해결하기 위해서 서버는 카드를 만들어줄 때마다 목록을 만들어 둔다. 첫번째로 방문한 친구 철수에게는 1234라는 카드를 발급해주면서 목록에 기록해두고, 첫번째 방문한 영희에게는 7890이라는 카드를 발급해주면서 목록에 기록해둔다.
그래서 철수가 아닌 사람이 서버가 발급한적 없는 6666이라는 위조 카드를 들고 저번에 방문했던 사람이라고 속여도 6666이라는 정보가 목록에 없으니 서버는 이 카드가 위조됬다는 것을 알아차릴 수 있는 것이다.
클라이언트가 최초 리퀘스트를 할 때,
세션이 없으면 이 로직이 계속 반복 되는 것.
사용자의 인증을 할 수 있고 세션을 통해서 어떤 민감한 정보에 접근을 할 때, 세션이 있는지 확인을 해서 값이 있으면 그 사람에 대한 정보를 응답해줄 수 있다.
서버는 클라이언트에서 요청할 때 응답을 해줘야 하는데 이 요청이 1000명이라고 생각해보자.
동접 300명을 처리할 수 있는 서버에 1000명의 요청이 들어오면 허용량인 300명을 처리할 동안 나머지 700명이 기다려야만 한다. 그래서 보통 동접이 많은 대형 사이트는 300짜리 서버를 3개를 운용해서 한 서버가 포화되면 다른 서버로 보내고 이 서버도 포화되면 또 다른 서버로 보내는 형태로 사용한다.
이렇게 서버가 포화될 때 다른 서버를 이용해 부하를 분산시키는 방식을 ‘로드 밸런싱'이라고 한다.
그런데 이러한 로드 밸런싱 환경에서 1번 서버에 요청을 보내 세션을 생성했는데, 재요청을 보낼때 1번 서버가 포화가 되서 다른 서버로 연결이 되면 어떻게 될까? 다른 서버의 입장에서는 이 클라이언트는 첫 방문자로 인식하게 된다. 왜? 다른 서버의 세션 저장소에는 해당 클라이언트의 세션 정보가 없기 때문.
이 문제의 해결 방법으로 Sticky Session이라는 것을 적용해서 클라이언트의 요청은 세션을 생성한 서버에만 전송하도록 하는 방법이 있다.
두번째 해결 방법은 생성된 세션을 모든 서버에 복제를 하는 방법이 있다.
하지만 이러한 방법은 모두 귀찮은 방법이다.
그래서 또 다른 방법으로는 모든 서버들이 하나의 DB에 세션 값을 넣어놓고 공유해서 사용하는 방법이 있다.
하지만 이 방법도 단점이 있는데, 서버의 세션 정보는 원래 서버 메모리에 접근해서 데이터를 가져오는 것이라 엄청 빠른 처리가 되는데 이 방법을 사용하면 메모리가 아닌 하드디스크에서 정보를 뒤져야 하기 때문에 엄청난 속도 저하가 발생하게 된다.
CPU가 데이터를 요청하면 이 요청은 바로 하드디스크로 가지 않고 먼저 RAM으로 간다. 하드디스크는 느리기 때문에 RAM을 먼저 뒤지는 것.
만약 RAM에 찾는 데이터가 없다면 그제서야 하드디스크를 뒤져서 데이터를 찾는다. 하드디스크에서 데이터를 찾으면 RAM에 찾은 데이터를 보내고, RAM에서 CPU에게 데이터를 보내게 된다.
그 다음 요청에도 같은 데이터를 요청하게 되면 데이터가 RAM에 남아 있기 때문에(캐싱) 하드디스크로 가지 않아서 I/O가 일어나지 않는다.
즉, 하드디스크로 간다는 것은 I/O가 일어난 다는 것. I/O가 일어나는 순간 속도가 100만배 정도 느려진다.
이 공유 세션 DB를 뒤지는 방식은 너무 느리기 때문에 그냥 DB를 사용하는 대신 메모리 서버를 사용한다.
메모리 서버는 하드디스크는 없고 RAM만 존재. 전기적 신호로 접근해 I/O가 일어나지 않아 빠르게 탐색 가능. 메모리 서버 중 대표적인 것이 'Redis'
이 세션의 문제점을 해결하기 위해서 JWT를 사용하는 것.
어떻게 해결하고 언제 쓰는가?
그것은 다음 포스트에서 알아보자.