JWT(Json Web Token) 와 세션(Session)

msung99·2022년 11월 28일
3
post-thumbnail

로그인과 관련한 이슈라면 다들 인증, 인가에 이어서 다양한 로그인 처리 방식이 존재한다는 것을 들어보셨을 겁니다. 그 중 현재 가장 대중적으로 사용되고 있는 로그인 인증 방식인 JWT 를 등장배경부터 시작해서 원리까지 알아보겠습니다.


인증(Authentication), 인가(Authorization)

우선 JWT 를 이해하기 위해선 인증(Authentication) 과 인가(Authorization) 에 대해 꼭 아셔야합니다. 이들이 뭘 뜻하는 것일까요?

  • 인증(Authentication)

쉽게말해 로그인이라 생각하면 됩니다. 내가 이 사이트에 가입된 회원임을 ,즉 특정 서비스에 일정 권한이 주어진 아이디와 패스워드 등을 통해서 말 그래도 인증을 받는 방식입니다.

  • 인가(Authorization)

앞선 인증과정을 통해 인증을 받은 사용자가 이후 서비스의 여러 기능들을 사용할 때, 즉 이를테면 내가 페이스북에 로그인으로 인증을 하고 "나서" 내 친구들을 목록을 보거나, 친구 게시글에 좋아요를 누르는 등의 내 계정으로"만" 할 수 있는 활동을 시도할 때 페이스북이 내가 로그인 되어있음을 알아보고 허가를 해주는 것입니다. 로그인이 유지되는 상태에서 일어나는 일이라고 보면 됩니다.

정리

  • 인증 : 사용자가 자기 계정을 사용하려고 할떄 로그인을 시켜서 해당 서비스에 대한 인증을 받는 것

  • 인가 : 인증을 받은 서용자가 서비스 안에서 돌아다닐때 서버가 해당 유저가 로그인 한 사용자라는 것을 알아보고 응 어서와~ 라고 허가해주는 것이다.

로그인 처리

매순간마다 수많은 사람들이 카카오 사이트에 들어와서 뉴스, 블로그, 메일 등등 서비스를 이용하고 있을겁니다. 웹 사이트 상에 존재하는 이런 링크에 대한 클릭들 하나하나가 다 요청이고, 카카오 사이트의 서버는 동시다발적으로 들어오는 무수한 사용자들의 요청에 응답해주고 있는 것입니다.

이 사람들중에 어떤 사람들은 로그인을 한 상태이고, 어떤 사람들은 안하고 그냥 방문한 상태일겁니다. 서버는 각 요청이 들어오래마다, 이를 보낸 사용자가 카카오 계정으로 로그인, 인증과정을 거친 상태인지 확인을 해서 그에 따라 이메일 접속, 댓글달기 등 로그인이 필요한 기능들에 허용을 해줄지 말지를 결정해서 응답해야 합니다.


매 요청마다 로그인을 시도한다면?

그러면 이런 생각이 들수있습니다. 내가 카카오 사이트에서 어디를 돌아다니고 뭘 하든간에 카카오에서 그 모든 활동에 대해 내가 로그인이 됐는지를 확인해야된다면, 그냥 단순히 내 아이디와 비밀번호를 크롬같은 브라우저에 저장해서 매 요청마다 보내서 로그인을 하면 되지 않을까요?


세션(Session) 과 JWT 의 등장

이렇게 하기엔 로그인이라는 것이 꽤 무거운 작업입니다. 일단 데이터베이스에 저장된 사용자 계정의 해시값 등을 꺼내온 다음에, 이것들이 사용자의 암호를 복잡한 알고리즘으로 계산한 값과 이리하는지 확인하는 과정들을 거쳐야 하기 때문이죠.

계산 자체도 빡신데다 데아터베이스에서 뭘 꺼내오는 것도 시간과 자원을 많이 잡아먹습니다. 이로써 매 요청마다 클라이언트 쪽에서 로그인을 시도하는 것은 무리일겁니다.

또한 매 요청마다 아이디와 비밀번호가 계속 왔다갔다마면 아무래도 보안상의 위험도 있습니다.

이들을 해결하기 위해 등장한 2가지 인가(Authorization) 방식이 바로 세션과 JWT 토큰입니다.


세션(Session)

세션을 왜 알아야하는데?

JWT가 무엇인지 알아보기전에, 세션(Session) 인증 방식에 대해 알아봅시다.
갑자기 JWT 가 아닌 세션에 대한 내용이 등장해서 다소 당황스러울 수 있지만, 왜 JWT 가 대중적으로 널리 사용되고 있는 보안방식인지 알기 위해선 이전에 자주 사용되던 인증 방식에 대해 간단히 짚고 넘어갈 필요가 있습니다.

(세션에 대한 자세한 내용은 따로 추후에 새로운 포스팅으로 다루도록 하겠습니다)


포스팅 참고

  • 설명에 앞서, 쿠키와 SessionId 에 대한 포스팅을 이전에 정리해놨으니 참고하실 분들은 참고바랍니다.

https://velog.io/@msung99/%EC%9D%B8%EC%A6%9D%EA%B4%80%EB%A0%A8-Header-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%BF%A0%ED%82%A4Cookie


세션이란

세션 방식은 어떤 유저가 로그인에 성공하면 SessionId 라는 정보를 브라우저(클라리언트)와 서버 양측에 쪼개서 저장하는 겁니다.

이 반쪽 SessionId 를 받은 사용자의 브라우저(크롬, 엣지 등) 이 발급받은 SessionId 를 Sessionid 란 이름의 쿠키(쿠키라는건 브라우저에 저장되는 정보다)로 저장하고, 이 브라우저는 앞으로 다음 사이트에 요청을 보낼 때마다 이 SessionId 를 실어보냅니다.

  • 이제 요청에 이 SessionId 가 실려오면 서버는 맞는 SessionId 짝이 존재하는지를 찾아보고, 존재한다면 인가(Authorization) 를 해주는 것이입니다.

이렇듯 SessionId 를 사용해서 어떤 사용자가 서버에 로그인 되어있음이 지속되는 이 상태를 "세션" 이라고 합니다.

다시말해, 어떤 사용자들이 현재 로그인해있는지를 가져다가 서버가 표딱지(SessionId) 반쪽들을 어디 둬가지고 기억을 해두고 있는겁니다.


세션의 한계

1. 메모리 저장공간 부족

서버측에서 SessionId 를 어딘가 메모리에 저장해두고 있을텐데, 사용자가 동시에 많은 접속을 하면 메모리가 부족해집니다.

2. 휘발성

그리고 이 메모리라는 것은 서버에 문제가 있어서 꺼져버리거나 하면 모든 SessionId값들이 죄다 날라가버리는 휘발성의 특징을 가지고있습니다.

  • 이렇듯 에러라는 것이 나타내서 말썽을 피우면, 즉 서버가 재부팅되어야 하는 상황이 온다면 메모리에 있던 것들은 죄다 날아가버립니다. 그렇다면 사용자들이 죄다 로그인이 튕겨서 다시 로그인을 해야하는 상황이 발생하게 됩니다.

(SessionId 값을 비교해서 인가를 시도하는 방식인데, 서버측에 존재하는 SessionId 값들이 싹다 날아가버렸으므로)

3. 로드밸런싱

더 골치아픈 경우는 서비스가 큰 규모인지라 서버를 여러대를 두고 사이트를 운영할때입니다.

사용자들의 요청이 들어오면, 요청에 대한 처리를 여러 서버들에 분산을 해서 처리(로드밸런싱) 하는 방식을 하는것인데, 만일 로그인 기능은 1번 서버에서 연결되서 하고, 그 다음에 이메일 페이지로 가능 요청은 3번 서버한테 가면

3번 서버입장에서는 1번 서버에서 생성한 SessionId 값을 보유하고 있지 않으므로 세션 유지가 제대로 되지 않고 인가(Authorization) 이 실패하는겁니다.

그렇다고 사용자의 요청이 각자 할당된 서버로만 보내지게 하는것도 번거로운 방법이다.

몰론 다른 방법으로 여러 서버들에 존재하는 SessionId 들을 공통으로 저장하는 데이터베이스를 구축할 수는 있으나, 대신 이렇게하면 속도가 엄청 느려집니다.


JWT(Json Web Token)

세션의 한계를 보완

세션처럼 토큰이라는 표를 출력해서 건내주는 방식이나, 세션과 달리 토큰을 쪼개지 않고 서버를 별도로 무언가를 기억하고 저장하고 있지 않습니다.

  • 서버는 토큰만 브라우저에게 발급해주고 그냥 잊어버립니다.별도로 저장하지 않음!

JWT의 전달방식

클라이언트는 서버에게 API 을 호출할때 아이디와 와 비밀번호를 보낼텐데,
그러면 서버에서는 받은 정보들을 암호화해서 JWT 토큰으로 만들어서 클라이언트에게 전달하는 방식입니다.


JWT의 구성성분

JWT 의 구성요소는 크게 Header, Payload, Signature 로 구분됩니다. 이들이 무엇인지 알아봅시다.


1. Header

어떤 방식으로 암호화할 것인지를 저장

구성요소1) 토큰의 타입

⇒항상 언제나 JWT 로 고정되어 있다. 즉 토큰의 타입이 JWT 로 할당되어있어야 JWT 토큰인것이다.

구성요소2) alg : algorithm 의 약자.

⇒ Signature(서명값) 을 만드는데 사용될 알고리즘이 지정됩니다. HS256등 여러 암호화 방식중에 하나를 지정할 수 있습니다.

2. Payload

클라이언트로부터 받은 내용을 저장합니다.

  • 해당 토큰을 통해 공개하기 원하는 내용 (ex. userIdx, 토큰 유효기간, 사용자의 닉네임이나 서비스사으이 접근레벨, 관리자 여부) 등을 저장합니다.

  • Claim : 토큰에 담긴 사용자 정보에 대한 데이터로, 사용자가 로그인을 하고나서 받는 토큰에 이 정보들이 이 클래임(Claim) 이러는 것을 실려오게 됩니다.

이 Claim 은 토큰 발급후에 클라이언트(사용자) 쪽에서 인증(Authetication) 이 필요한 요청을 보낼떄마다 서버에게 보냅니다.
사용자가 토큰을 받아서 가지고있는 토큰 자체에 이러한 Claim 정보가 들어있으면 서버가 매 요청마다 일일이 데이터베이스에서 뒤져봐야 하는 과정들이 줄어듭니다.

3. Signature (서명값)

앞서 살펴본 Header, Payload, 그리고 서버가 별도로 보유하고 있는 Secret key 키를 가지고 암호화 알고리즘(ex. HS256) 을 돌려서 생성된 값

  • 암호화 알고리즘이라는것이 한쪽 방향으로는 계산이 돼도 반대쪽으로는 안되는 것이라, 서버만 알고있는 그 비밀 값(secret key) 를 찾아낼 방법이 없다. 해커가 토큰들을 싹다 탈취해서 백날 들여다봐도, 그리고 글자 하나만 바뀌어도 Signature 값이 완전히 달라지는 것이라
    Payload 를 수정해서 유효한 Signature 값이 나오려면 서버에 숨긴 비밀 키(Secret key) 를 알고 있어야해서 이를 조작하지 못하는것입니다.

  • 서버는 요청에 토큰 값이 실려서 들어오면 HEADER, Payload 의 값을 서버의 Secret key 와 함께 돌려봐서 계산된 결과값이 Signature 값과 일치하는 결과가 나오는지 확인합니다.

    만일 Payload 의 정보가 서버가 아닌 누군가에 의해 조금이라도 수정되면 당연히 안 맞습니다. 정보를 조작한 사용자이거나 해커인걸로 간주돼서 거부됩니다.

    Signature 값과 계산값이 일치하고, 유효기간도 지나지 않았다면 그 사용자는 로그인 된 회원으로써 인가(Authorization) 를 받는것입니다.


JWT 발급, 처리 흐름정리

정말 간단하게 설명해보자면, 아래와 같습니다.

  1. 클라이언트가 서버에게 ID, PWD 를 보내면
  2. 서버가 JWT Token 을 발급해준다.
  3. 클라이언트는 서버에게 ID, PWD 를 보낼 필요가 없어진다.
  4. 앞으로 자동 로그인 api 를 호출시에 JWT 를 보낸다.
  5. 그러면 서버는 클라이언트로 부터 JWT 를 가지고 복구화 작업을 합니다.
  • 즉, 클라이언트로 부터 받은 JWT 를 암호화된 것을 풀어서 다시 클라이언트에게 전송해준다. 이떄 전송할때 Reponse 값에다 이 놈 회원맞어! 라고 Response 를 보내주는 것입니다.

Local Storage

앞서 설명하길, JWT는 서버에 유저정보(Token)를 들고있는 것이 아닌 클라이언트에 들고 있는 것이라고 했습니다. 그렇다면 클라이언트는 발급받은 토큰을 어디에 저장할까요?

클라이언트는 Mysql과 같은 Query를 사용하지 못합니다.
따라서 클라이언트는 local storage라는 곳에 JWT 를 저장합니다.

Local Storage 는 모든 플랫폼(안드로이드, ios, 웹 등등) 에 존재하는 클라이언트의 저장소입니다.

  • 즉 서버로부터 발급받은 jwt 는 로컬 스토리지에 저장합니다.

그러면 자동 로그인 API 를 호출시에, 로컬 스토리지에 저장된 토큰값을 서버에 보내는 방식으로 토큰을 유지하면 됩니다.

로그아웃시 Local Storage 에 있는 JWT 값을 삭제하면 됩니다.
JWT 는 서버에 저장할 필요없이, 클라이언트가 local storage 에 저장하고 있다가 서버에 넘겨주면 되는거죠.


JWT가 세션을 대체할 수 있을까?

안타깝게도 JWT 가 완전히 세션을 대체하지는 못힙니다.

세션처럼 stateful 해서 모든 사용자들의 상태를 기억하고 있다는건 구현하기 부담되고 고려사항도 많겠지만, 이게 되기만 하면 기억하는 대상의 상태들을 언제든 제어할 수 있다는 의미가 되기 떄문입니다.

예를들어 한 기기에서만 로그인 가능한 서비스를 만들고 시은경우, PC 에서 로그인한 상태의 어떤 사용자가 핸드폰에서 또 로그인하면 PC 에서는 로그아웃되도록 기존 세션을 종료할 수 있습니다.


마치며

JWT 와 세션을 계속 대조.비교하며 JWT 가 무엇인지 알아보았습니다.
이런 JWT 에는 사실 Access Token, Refresh Token 이라는 것으로 또 구분됩니다.

또한 OAuth, Social Token 과 같은 다양한 보안관련 기능들이 있는데, 이들이 무엇인지는 조만간 새로운 포스팅으로 또 찾아뵙겠습니다.

profile
블로그 이전했습니다 🙂

0개의 댓글