세션 vs 토큰과 JWT

Juhyang·2022년 3월 7일
0

인증과 인가

인증

  • 로그인
  • 내 사이트에 가입된 회원 / 권한이 있는 회원임을 아이디와 pw로 인증받는 것

인가

  • 위의 인증을 받고'나서' 내 계정으로 '만' 할 수 있는 활동을 할 때, 로그인이 되어있다는 것을 서버가 알고 이 사용자를 허용해주는 것
    - JWT는 인가에 가깝다.

즉, 사용자가 어떤 활동을 할때 -> 서버는 이게 로그인 된 사용자인지 (인증과정을 거친) 확인 -> 그에 따라서 로그인을 해야만 할 수 있는 작업에 대한 권한을 부여해줌. 인증이 안됐다면 당연히 거부.

이 인증과 인가 방식을 고민 많이 해봐야 하는 이유

- 만약 DB에서 사용자의 계정에 따른 해시값을 꺼내오고 알고리즘으로 계산해서 암호가 일치하는지 확인하는 방식을 사용할 경우... -> DB에서 뭘 꺼내온다는것 자체가 고비용.
- 요청마다 id와 pw를 실어서 보내면.. -> 당연히 보안에 매우 취약함.
- 그래서 사람들이 세션방식과 토큰 방식을 고민하게 되었다.

세션 방식

동작 방식

  1. 사용자가 로그인에 성공하면 서버가 세션 표딱지를 출력해준다. (마치 영화관 티켓 같이!)
  2. 이 표딱지를 반으로 잘라서 반은 사용자의 브라우저, 반은 서버의 메모리에 저장한다.
  3. 여기서 브라우저는 이 표를 SessionId란 이름의 쿠키로 브라우저에 저장한다.
    • 여기서 쿠키 vs session vs localstorge 차이 따로 정리
  4. 이제 브라우저는 앞으로 요청을 보낼 때 마다 이 표딱지(세션 아이디)를 실어서 서버에 보낸다.
  5. 서버는 해당 표딱지가 오면, 메모리에서 맞는 짝이 있는지 찾는다.
  6. 있다면 인가 해줌!

이 1-6번까지의 단계. 즉 세션 아이디를 사용해서 어떤 사용자가 서버에 로그인 되어있는것이 지속되는 상태세션 이라고 한다.

세션 방식의 단점

  1. 메모리에 표딱지를 저장하다보니, 메모리가 부족해 질 수 있다.
  2. 메모리는 휘발성이기 때문에, 서버가 재부팅되면 모두 날아간다.
  3. 만약 서버를 여러대 둔다면?
    • 각 서버에 필요한 요청을 할당시키기도 까다롭고... 서버별로 가지고 있는 표딱지도 다르고..
    • 물론 해결 방법은 있다. (레디스 등 메모리형 데이터 베이스 서버 사용) 그러나 이것도 휘발성에 대해 감수해야한다..

서버가 복잡한 구성과 환경에서는, 어떤 상태를 기억해야한다는 것이 굉장히 복잡 하다.
그래서 토큰 방식인 JWT(Json Web Token) 을 고민하게 되었다!

토큰 방식

동작 방식

  1. 사용자가 로그인에 성공하면 토큰이라는 표를 출력해준다.

  2. 앞서 세션과는 달리, 반으로 자르지 않고 통째로 브라우저에만 넘겨준다. 즉 서버는 기억하고 있는게 하나도 없음!

  3. 토큰을 들여다보면, 중간에 마침표로 3단계로 구분히 됨을 볼 수 있다.
    xxxx.yyyy.zzzz

  4. 이것은 크게 (1)Header , (2)Payload, (3) Signature 로 구성되어있고 base24 암호화 방식을 사용하고 있다.

    (1) Header - 토큰의 정보
    (2) Payload - 인가에 필요한 정보가 담겨 있다.
    - 페이로드를 디코딩 해보면 Json 형식으로 여러개 나누어진다.
    - 이 부분은 유효기간, 사용자 정보 등 이 담겨있고 이것을 클레임 이라고 한다.
    - 즉 Payload 는 클레임의 집합!
    (3) Signature - 특수한 서명값

  5. 즉 서버로 토큰을 보내면, 클레임들만 확인해서 필요한 인가를 처리하면 되므로 서버에서 일일이 DB에서 안뒤져봐도 된다.

1-5번 방식을 통해 세션의 단점을 보완할 수 있다!

근데, 토큰 값을 base24로 암호화 하면, 조작이 너무 쉽지 않나?

  • 만약 누가 악의적으로 payload 를 조작해서 관리자 권한으로 인가받으면..?
  • 누가 남의 토큰을 탈취한다면...?

-> 그래서 1,3번 파트인 Header와 Signature를 사용합니다.

(1)Header + (2)Payload === (3)Signature?

위에서 간단히만 설명했던 (1),(3)번 파트를 이제 자세히 정리하자면..

(1) Header - 토큰의 정보를 담고 있음.
- type : 토큰의 타입을 지정. JWT!
- alg : (3)번의 서명값을 검증할 해싱 알고리즘 지정.
대표적으로 HMAC SHA256와 RSA가 있다.

(3) Signature - 특수한 서명값.
- (1)번과 (2)번을 합친 값을 비밀키로 해쉬 하여 생성한 값
- 서버만 비밀키를 알고있다!

결론 : (1)+(2)값 비밀키로 해쉬한 값 === (3) 이고, (2)의 유효기간이 안넘었다면 해당 사용자는 인가받음!

즉!! 서버는 사용자의 상태를 따로 저장할 필요 없이 비밀키만 가지고 있다면, 토큰을 스캔해서 사용자들을 걸러낼 수 있다.
이렇게 JWT 방식처럼 시간에따라 바뀌는 상태값을 가지지 않는것을 Stateless 라고 한다.
( 이것의 반대인 세션은 Stateful !!)

토큰 방식의 단점

  1. 세션은 stateful이라서 기억하고 있는 대상의 상태들을 언제든지 제어할 수 있다. 근데 토큰은 stateless 므로 통제를 할 수 없다.
    • 토큰 방식에서 모바일에서 로그인한 사용자가 pc로 로그인 했을 경우 기존의 로그인을 삭제하려면?
  2. 토큰을 탈취당하면 해당 토큰을 무효화 할 방법이 없다.

단점을 보완하는 Access Token과 Refresh Token

위의 단점을 완벽히 해결하는것은 아니지만, 어느정도 보완할 수 있는 방법이 있다.

  1. 토큰 수명이 아주 짧은 (수분~수시간 내) Access Token과 보통 2주정도로 잡혀있는 긴 Refresh Token을 발급한다.
  2. 둘 다 발급하여 브라우저에게 보낸 후, Refresh Token 값에 상응하는 값은 DB에 저장한다.
  3. 사용자가 Access Token의 수명이 다하면 Refresh Token을 서버에 보낸다.
  4. 서버는 Refresh Token 의 상응값을 대조해보고 일치한다면 다시 Access Token을 발급해준다.

즉, 인가받기 위해서는 유효한 Access Token이 있어야하고, 이 Access Token를 재발급 받기 위해선 Refresh Token이 필요한 것이다.

해당 방법을 통해서...

  1. Access Token이 탈취당해도, 사용할 수 있는 기간이 짧다.
  2. 앞서 예시를 들었던 강제 로그아웃을 하고 싶다면?
    • Refresh Token 상응값을 DB에서 지워버려서 Access Token 이 갱신 안되도록 하면 된다.

그래도 어쩔 수 없는 한계점

짧더라도 Access Token 이 살아있는 동안 발생하는 문제는 어쩔 수 없는것이 현재의 한계점이다.
즉 우리 서비스에서 JWT 방식이 문제가 없는지 고민해보고 사용해봐야 할 것이다.

참고문서
https://velopert.com/2389
https://jwt.io/introduction
https://dreamaz.tistory.com/22
유튜브

그래서 컬리는 어떤 방식?

다음 이야기에서 www.v2와 nx의 인증/인가 방식이 다르다고 하여 이를 정리해보았습니다.

profile
kurly - commerce web development

0개의 댓글