웹 서핑을 하면서 어떤 사이트에 들어가면 쿠키를 설정하라는 문구를 본 적이 있을 거예요. 이 쿠키 때문에 쇼핑 사이트에 로그인하지 않아도 장바구니에 물건을 담아두거나 검색 기록에서 이전에 입력했던 검색어들을 찾아볼 수 있습니다. 나의 웹 서핑 내역이 마케팅과 광고에 활용되는 것도 쿠키를 통해 이뤄지는 일이죠.
사용자는 브라우저의 설정 화면이나 개발자 도구에서 쿠키를 확인하고 수정, 삭제할 수 있습니다. 다만 쿠키는 당사자뿐만 아니라 제 3자가 조회하는 것도 가능하기 때문에 개인 정보를 담은 내용이나 보안상 민감한 정보를 저장하는 데에는 적합하지 않습니다. 따라서 혹여 남에게 탈취되거나 사용자에 의해 조작되어도 크게 문제되지 않을 정보를 브라우저에 저장함으로써 웹사이트 이용을 편리하게 해 주는 것이 쿠키입니다. 예를 들면 자주 보는 웹툰 목록이나 웹 페이지의 다크 모드 설정 여부 등과 같은 간단한 정보 말이죠.
쿠키는 크롬이나 사파리 같은 브라우저에 저장되는 작은 텍스트 조각입니다. 브라우저는 사용자의 컴퓨터에 설치된 소프트웨어이므로 쿠키는 사용자가 갖고 있는 정보라고 할 수 있죠.
장바구니, 사이트 검색내역, 사이트 팝업설정(오늘 하루 보지 않기)
1. 브라우저(클라이언트)가 서버에 요청을 보낸다.
2. 서버는 클라이언트의 요청에 대한 응답을 작성할 때, 클라이언트 측에 저장하고 싶은 정보를 응답 헤더의 Set-Cookie에 담는다.
3. 이후 해당 클라이언트는 요청을 보낼 때마다, 매번 저장된 쿠키를 요청 헤더의 Cookie에 담아 보낸다.
보안에 취약합니다.
웹 브라우저마다 쿠키에 대한 지원 형태가 다르기때문에 브라우저간 공유 불가능합니다.
클라이언트는 세션 id를 쿠키를 통해서 기억합니다.
브라우저에 세션id를 저장해둔 클라이언트는 다음 요청때마다 헤더의 cookie에 세션id를 담아서 전송합니다.
서버는 클라이언트가 보낸 요청의 쿠키에 담긴 세션id와 세션 스토리지에 담긴 세션 id를 대조해 인증상태를 판단하는 것입니다.
(즉, 세션은 쿠키를 기반으로 한다.)
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
웹사이트에 아이디와 비밀번호를 입력해서 로그인하면 해당 사이트의 회원에게만 허용된 기능들을 사용할 수 있습니다. 마이페이지를 클릭해서 내 정보를 볼 수도 있고, 회원 전용 게시판의 글쓰기 버튼을 클릭해서 질문을 남기거나 리뷰를 쓸 수도 있죠.
문제는 이와 같은 클릭 하나하나는 매번 서버에게 새로 보내는 익명 편지와도 같아서 사이트에 로그인을 하는 등의 이전 행동들과 연결되어 있지 않다는 것입니다. 다시 말해 서버는 아이디와 비밀번호를 입력해 로그인에 성공한 사용자와 로그인한 다음 마이페이지 버튼을 누른 사용자가 동일 인물임을 알지 못한다는 것입니다. 그렇기 때문에 사용자가 사이트에 로그인한 상태라는 점을 서버에 인증하지 못하면 클릭을 할 때마다 반복해서 아이디와 비밀번호를 서버에 제공해야 합니다. 이런 번거로움을 해결하기 위해 사용하는 것이 바로 세션입니다.
사용자가 사이트에 한 번 로그인하면 유효기간이 끝날 때까지 더 이상 아이디와 비밀번호를 입력하지 않아도 되도록 사용자가 이미 서버로부터 인증받았음을 증명해 주는 세션이라는 증서가 필요합니다. 사용자가 서버에 올바른 아이디와 비밀번호로 로그인에 성공하면 서버는 세션 아이디라는 데이터를 만듭니다. 보통은 ‘2sd98dbawix4’와 같은 식으로 알파벳과 숫자가 혼합된 형식을 갖고 있습니다. 서버는 영화관에서 티켓을 보관용 부분만 찢어 건네주듯 세션 아이디를 사용자에게 전달하고, 메모리에 아이디 사본을 어떤 사용자의 것인지 적어서 보관합니다.
사용자는 서버로부터 받은 세션 아이디를 쿠키로 저장한 다음 앞으로의 모든 요청에 함께 전달합니다. 친구 목록을 볼 때, 댓글을 작성하거나 삭제할 때, 구매한 상품 내역을 볼 때도 서버에게 세션 아이디를 적은 편지를 보냅니다.
서버는 사용자에게서 친구 목록을 보겠다는 요청을 받으면 그 편지에 세션 아이디가 적혀있는지를 확인합니다. 아이디가 있다면 서버가 보관하고 있는 세션 아이디 중에 동일한 정보가 있는지 찾아보고 그것이 누구의 계정인지도 알아내죠. 그렇게 편지를 보낸 사람이 누구인지 파악한 다음 해당 사용자의 친구 목록을 보내주는 것입니다.
서버는 로그인 된 유저의 모든 정보를 저장, 해당 정보를 이용하여 새로운 기능을 추가할 수 있습니다.
그리고 세션 저장소를 필요로합니다.
세션db -> 세션 저장소는 로그인 시 사용자 정보를 저장하고, 열쇠로 사용할 수 있는 세션 id를 만듭니다. 그리고 http 헤더에 실어 클라이언트에게 보냅니다. 브라우저는 세션id를 포함하는 쿠키를 저장하고 있으며 인증이 필요한 요청에 해당 쿠키를 끼워 서버에 request를 보내죠.
서버는 누가 로그인 했는지 저장하고, 세션db가 있기 때문입니다. 다 알고싶으면 db를 사고 유지해야합니다. 유저가 늘어나면 db도 커져야하는데 redis(빠르고 저렴)를 주로 사용합니다.
특정 유저를 쫓아내고 싶을때 그냥 세션을 삭제하면 됩니다.
인스타 강제 로그아웃 처럼 사용하고 넷플처럼 계정 공유 숫자를 제한할 수 있습니다.
1.사용자가 로그인을 합니다.
2.서버에서는 계정 정보를 읽어 사용자를 확인 후, 사용자의 고유 ID 값을 부여한 후 세션 저장소에 저장하고, 이와 연결되는 세션 ID 를 발행합니다.
3.클라이언트는 서버에서 해당 세션 ID 를 받아 쿠키에 저장 한 후, 인증이 필요한 요청마다 쿠키를 헤더에 끼워 보냅니다.
4.서버에서는 쿠키를 받아 세션 저장소에서 확인 한 후, 일치하는 정보를 가져옵니다.
5.인증이 완료되고 서버는 사용자에 맞는 데이터를 보내줍니다.
메모리에 로그인되어 있는 사용자의 상태를 보관해야 합니다.
사용자의 상태를 원하는대로 통제가능합니다.
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
세션 방식은 안전하고 효과적이지만 단점도 있습니다. 서버는 요청마다 함께 딸려 오는 세션 아이디를 바로바로 확인할 수 있도록 로그인한 사용자의 아이디를 메모리라는 ‘책상’에 올려둡니다. 메모리에 올려둔 데이터를 빠르게 확인할 수 있다는 장점이 있는 대신 공간이 한정되어 있죠. 서버에 동시 접속하는 사용자가 많아지면 메모리 공간이 부족해져서 서버에 부하가 걸리고 화면이 움직이지 않는 등의 문제가 발생할 수 있습니다.
메모리 공간을 많이 차지하는 세션 방식의 대안은 로그인한 사용자에게 세션 아이디 대신 토큰을 발급해 주는 것입니다. 이러한 토큰에는 특수한 수학적 원리가 적용되어 있어서 마치 위조 방지 장치가 있는 지폐처럼 서버만이 유효한 토큰을 발행할 수 있습니다.
그렇기 때문에 토큰을 받아간 사용자가 이를 쿠키로 저장해 두고 필요할 때마다 제시하면 서버는 따로 책상에 올려놓은 것을 확인할 필요 없이 자기가 발급한 토큰임을 알아보고 사용자의 요청을 허가해 주는 것입니다. 더 이상 이미 로그인한 사용자의 티켓을 책상(메모리)에 올려 두고 있을 필요가 없으니 서버 부하를 줄일 수 있는 것이죠.
토큰 방식은 해당 서버만이 만들 수 있는 토큰을 발급함으로써 상태를 저장하지 않고도 사용자의 로그인 여부를 파악할 수 있도록 합니다.
물론 토큰 방식에도 한계는 있습니다. 여러 기기에서의 로그인을 제한하기 위해 필요한 때 에 로그인되어 있는 사용자를 서버가 강제로 로그아웃을 시킬 수 있어야 하는데, 토큰 방식에서는 이것이 불가능합니다. 한 번 발행한 토큰은 유효기간이 끝나기 전까지 따로 통제할 수 없기 때문에 세션에 비해 토큰 정보를 탈취 당할 가능성이 높습니다. 그러나 토큰은 쿠키처럼 만료 기간을 정할 수 있어서 만료 시간을 짧게 지정해 피해를 줄일 수 있습니다. 토큰방식은 쿠키와 세션을 적절히 섞은 것과 비슷합니다.
(Facebook로그인, Goggle로그인 등이 모두 토큰을 기반으로 인증)
1. 사용자가 로그인을 합니다.
2. 서버에서는 계정 정보를 읽어 사용자를 확인 후, 사용자의 고유 ID 값을 부여한 후 기타 정보와 함께 Payload 에 집어넣습니다.
3. JWT 토큰의 유효기간을 설정합니다.
4. 암호화할 Secret key 를 이용해 Access Token 을 발급합니다.
5. 사용자는 Access Token 을 받아 저장 후, 인증이 필요한 요청마다 토큰을 헤더에 실어 보냅니다.
6. 서버에서는 해당 토큰의 Verify Signature 를 Secret key 로 복호화한 후, 조작 여부, 유효기간을 확인합니다.
7. 검증이 완료되었을 경우, Payload 를 디코딩 하여 사용자의 ID 에 맞는 데이터를 가져옵니다.
상태를 따로 기억해 둘 필요가 없습니다.
한 번 로그인한 사용자의 상태의 토큰
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
jwt를 사용하면 생성된 토큰 추적할 수 없습니다. 서버가 아는 것은 토큰이 유효한지만 알 수 있죠
세션과 다르게 저장소(db)를 따로 살 필요 없고 강제 로그아웃 같은 것을 할 수 없습니다. 해당 토큰이 만료되기 전까지 유효하기 때문이죠.
데이터를 사인하고 유저에게 보내고 데이터 돌려받을 때 유효성 검증할 수 있습니다.
JWT (JSON Web Token)은 인증에 필요한 정보들을 암호화시킨 JSON 토큰을 의미합니다. JWT 기반인증은 JWT 토큰을 HTTP 헤더에 실어 서버가 클라이언트를 식별하는 방식이죠.
JWT는 JSON 데이터를 Base64 URL-safe-Encode 를 통해 인코딩을 직렬화 한것이며, 토큰 내부에는 위.변조 방지를 위해 개인키를 통한 전자서명도 들어가 있습니다. 따라서 사용자가 JWT를 서버로 전송하면 서버는 서명을 검증하는 과정을 거치고 검증이 완료되면 요청한 응답을 돌려줍니다.
헤더.내용.서명 문자열 조합
위에서 Header는 JWT에서 사용할 타입과 해시 알고리즘의 종류가 담겨있으며, Payload는 서버에서 첨부한 사용자 권한 정보와 데이터가 담겨있고,
Payload에는 해독이 가능하기 때문에 중요한 정보는 포함해서는 안됩니다.
Signature에는 Header, Payload를 Base64 URL-safe Encode를 한 이후 Header에 명시된 해시함수를 적용하고, 개인키로 서명한 전자서명이 담겨있습니다.
코로나 qr코드
1. 사용자가 로그인을 한다.
2. 서버에서는 계정 정보를 읽어 사용자를 확인 후, 사용자 고유ID값을 부여한 후, 기타 정보와 함께 Payload에 넣는다.
3. JWT의 유효기간 설정
4. 암호화할 SECRET KEY를 이용하여 Access Token을 발급 한다.
5. 사용자는 Access Token을 받아 로컬 스토리지(혹은 쿠키)에 저장한 후, 인증이 필요한 요청마다 토큰을 헤더에 실어서 보낸다.
6. 서버에서는 해당 토큰의 Verify Signature을 SECRET KEY로 복호화한 후, 조작여부, 유효기간을 확인한다.
7. 검증이 완료되면, Payload를 디코딩하여 사용자의 ID에 맞는 데이터를 가져온다.
Header와 Payload를 가지고 Signature를 생성하여 데이터 위.변조를 막을 수 있습니다.
인증 정보에 대한 별도의 저장소가 필요없다.
토큰 기반으로 다른 로그인 시스템에 접근 및 권한 공유가 가능하다.
(Facebook로그인, Goggle로그인 등이 모두 토큰을 기반으로 인증)
JWT는 발급한 후 검증만 하면 되기 때문에 Stateless한 서버를 만드는 입장에선 아주 큰 장점이다.
이미 발급된 JWT에 대해서는 돌이킬 수 없습니다.
세션 / 쿠키의 경우 만일 쿠키가 악의적으로 이용되고 있다면, 해당하는 세션을 지워버리면 됩니다.
하지만 JWT는 한번 발급되면 유효기간이 완료될 때까지 계속 사용이 가능 합니다.
따라서 악의적인 사용자는 유효기간이 지나기 전까지 정보를 털어갈 수 있죠.
Payload의 정보가 제한적입니다.
Payload는 암호화 되지않기 때문에 디코딩하면 누구나 정보를 확인할 수 있습니다.
따라서 유저의 중요한 정보들은 Payload에 넣을 수 없죠.
인증이 필요한 요청이 많아질수록 서버의 자원 낭비가 발생한다.
서비스가 더 커지고 유저계정을 좀 더 잘관리하고 싶으면 세션으로 옮기는것이 좋습니다.