[Authorization] Session vs Token

이예빈·2022년 4월 27일
1

Authorization?

사용자 로그인 후 로그인 상태를 유지하지 않는다면 어떤 일이 발생할까?
만약 네이버에서 블로그 글을 작성하는 상황이라면, 로그인을 했음에도 블로그글을 작성할 때에도 사용자 아이디와 비밀번호를 함께 작성한 블로그글과 함께 서버에 전달해야하고 서버는 또 다시 그 아이디와 비밀번호를 유저테이블에서 비교후 사용자 인증을 거치고 블로그 글을 저장해야하는 번거롭고 소모적인 작업을 매번 반복해야할 것이다.

위와 같은 불편한 작업을 줄이고자 '로그인 상태를 유지' 하는 것이 필요한 것이다.

쉽게 말해 로그인을 'Authentication(인증)' 이라한다면, 로그인상태를 유지하는 것 'Authorization(인가)'라고 한다.

'Authorization'을 위한 방법엔 크게 2가지가 있는데, 1) Session 방식 2) Token방식이 있다.

Session을 활용한 Authorization

전통적으로 많이 사용되어온 '세션'방식은 어떤 식으로 사용자 인가를 하는지 알아보자.

  1. 사용자가 서버로 로그인 요청을 한다.
  2. 서버는 사용자가 보내온 아이디와 패스워드를 확인하여 회원이 맞다면 '세션 표딱지'란 걸 출력하고 서버측에 저장해둔다.
    ( 세션이 저장되는 장소는 메모리일수도, 하드디스크일수도, 데이터베이스일수도 있다.)
  3. 이 '세션 표딱지'의 일부를 클라이언트. 즉, 크롬이나 엣지 브라우저에 전달한다.
  4. 클라이언트는 이 표를 Session ID란 이름의 쿠키로 저장하고, 인증이 필요한 요청마다 헤더에 이 session ID를 함께 실어 보낸다.
  5. 요청을 받은 서버측에선 세션 저장소에서 session ID를 검증하고 인증이 완료되면 해당 사용자에게 맞는 응답을 보내주게 된다.

장점

  • 사용자의 정보를 담지 않고 sessionID를 주고받으므로 sessionID가 탈취되어도 중요 정보를 볼 순 없다.
  • HTTP only옵션을 설정하여 보안을 좀 더 강화할 수 있다.
  • 서버단에서 세션을 관리하므로 특정 사용자의 보안이 의심되는 경우 로그아웃처리가 쉽다.
  • 또 위와같은 점으로 인해 한 아이디로 여러 기기에 로그인 되는것을 방지할 수도 있다.
    ( 서비스의 성격에 따라 다르겠지만 한아이디당 한 기기 로그인이 필요한 서비스라면.. )

단점

  • 만약 서버의 메모리에 세션정보를 저장해 두었다면, 동시 접속이 많아질 경우 메모리가 부족해 질 수 있다.
  • 또 서버에 문제가 생겨 재부팅해야하는 상황이라면, 메모리에 있는 것들은 다 날아가게 된다.
  • 서비스의 규모가 커져서 여러대의 서버로 운영해야하는 상황이라면, 어느 서버로 요청이 가게될지 모르니 세션유지가 어렵다. ( 각각의 서버마다 세션 저장소를 둔다 해도 비효율적이다.)
  • 다른 방법으로 이 세션 정보를 공용 데이터베이스 서버에 넣어두거나 더 흔히는 레디스나 MenCached같은 메모리형 데이터베이스 서버에 저장해두기도 한다.

Token을 활용한 Authorization

session방식으로 사용자 인가를 구현했을 때 여러 서버를 운용하는 서비스의 경우 세션정보를 어디에 어떻게 보관할 것인지 구상하고 관리하는 등 설계가 꽤 복잡하다는 단점이 존재했다.

그래서 그런 부담없이 인가를 구현하기 위해 고안된 것이 "Token 방식인 JWT(Json Web Token)"이다.

token방식으로는 어떻게 사용자 인가를 하는지 알아보자.

  1. 사용자가(클라이언트는) 서버로 로그인 요청을 보낸다.
  2. 서버는 사용자가 보내온 계정정보를 읽어 사용자를 확인 후, token을 발급하여 클라이언트로 전달합니다.
  3. 클라이언트는 token을 받아 저장한 후, 요청마다 헤더에 token을 실어 보낸다.
  4. 요청을 받은 서버측에선 서버에만 저장되어있는 secret key로 해당 token의 verify Signature라는 것을 복호화하고 조작여부와 유효기간을 판단한다.
  5. 검증이 완료되면 사용자에게 맞는 데이터를 응답으로 보낸다.

위의 과정 2번에서 보듯 서버는 token을 발급하여 클라이언트에게 전달하기만하고 서버측에 따로 해당 token을 저장해두진 않는다.
( 이점이 session방식에선 세션저장소를 필요로하는 것과는 대조적이다. )

사용자에게 발급되는 token은 위사진의 왼쪽과 같은 형태를 갖게된다.
마침표(.)로 끊어져서 세 부분으로 나뉘는데
각각 header, payload, verify signature로 구분된다.

  • payload

    • base 64로 디코딩해보면 JSON형식으로 여러정보들이 들어있다.
    • 이 토큰을 누가 누구에게 발급했는지, 유효기간은 언제까지인지, 사용자의 닉네임, 관리자여부 등과 같은 토큰을 통해 공개하길 원하는 내용을 원하는대로 담을 수 있다.
    • 이렇게 토큰에 담긴 사용자 정보 등의 데이터를 claim이라 부른다.
  • header

    • header를 디코딩해보면 type과 alg정보가 담겨있다.
    • type은 항상 JWT로 고정값이고 alg는 알고리즘의 약자로 verify signature를 만들때 사용될 알고리즘이 들어간다.
      ( 위의 사진에선 HS256이란 알고리즘이 쓰였다는걸 확인할 수 있다.)
  • verify signature

    • verify signature는 header와 payload 그리고 서버에만 감춰둔 secret key를 암호화 알고리즘에 넣고 돌려 만들어진다.
    • 이 알고리즘 이란 건 암호화하는 것은 가능하지만 복호화하는 것은 불가능하기때문에 이 token들이 아무리 탈취되더라도 서버만 알고있는 secret key를 알아낼 수는 없다.
    • 따라서 서버는 요청에 token값이 실려들어오면 payload와 header의 값을 서버의 secret key와 함께 돌려봐서 계산된 결과값이 해당 token에 있는 verify signature와 일치하는 결과가 나오는지 확인한다.

=> 그러므로 이제는 서버는 사용자들의 상태를 어딘가에 따로 기억해 둘 필요 없이 secret key만 갖고 있으면 요청이 들어올 때마다 token을 비교해 사용자를 걸러낼 수 있게된다.

이러한 것을 stateless하다고 말한다. (반면, 일일히 사용자 저마다의 세션정보를 서버가 알고 있어야하므로 session 방식은 stateful하다.)

그렇다면 JWT를 사용해야할까?

단점

  • 위에서 말했듯 session은 stateful해서 사용자의 상태를 기억하고 있기때문에 언제든 제어할 수 있다는 장점이 있다. 반면 JWT는 그렇지 않아서 언제든 사용자를 제어하긴 힘들다는 단점이 있다.

  • 그렇다고 session방식처럼 발급한 token을 서버측 어딘가에 저장해두는 건 session방식과 다를 바 없기 때문에 token방식으로써의 의미가 없어진다.

  • 더 심각한 경우는 token이 탈취된 경우 해당 token을 무효화할 방법이 없다는 점이다.
    (이 때문에 JWT만으로 인가를 구현한 곳은 생각보다 많지 않다고 한다. )

단점을 보완하기 위한 방법은?

위의 치명적인 단점을 보완하기 위해 쓴 방법들이 있는데
token만료시간을 매우 짧게 주는 것이다. 수명이 짧으므로 서비스를 이용하는 동안 지정된 시간이 지났을 때마다 다시 로그인을 시키는건 사용자 입장에서 불편하므로

로그인을 하고나면 2개의 토큰을 준다.
"access token"과 "refresh token"이다.

(앞으로 말하게 될 인가 방식은 여러 방법 둘 중에 하나일 뿐이라는 걸 염두하고 보자)

  1. 서버는 access token과 refresh token을 발급하여 클라이언트에게 보내고 나서 refresh token의 상응값을 데이터베이스에도 저장한다.

  2. 클라이언트는 데이터 요청을 할때 access token을 보내는데 수명이 다했다면 refresh token을 보낸다.

  3. 서버는 그걸 데이터베이스에 저장된 값과 대조해본 뒤 맞다면 새로운 access token을 발급해준다.

  4. 이제 이 refresh token만 안전하게 관리된다면 access token이 만료될때마다 다시 로그인할 필요 없이 새로 발급할 수 있는 것이다.

=> 이렇게 하면 중간에 access token이 탈취당해도 새로 access token을 발급받진 못하니까 오래 쓸 수는 없고 누군가 강제 로그아웃을 시키고 싶다면 그 사용자의 refresh token을 데이터베이스에서 지워서 토큰 갱신을 막으면 된다.
( 물론 유효기간이 아직 남은 access token이라면 그 잠시 동안은 제어할 수 없다..)

결론

JWT의 장단점, Session의 장단점을 고려해 서비스에 적합한 인가방식을 선택하자!

참고
https://www.yalco.kr/48_jwt/
https://tansfil.tistory.com/58?category=475681
https://jwt.io/

0개의 댓글