Session & JWT

훈이는못말려·2023년 7월 17일
1
post-thumbnail

인증 (Authentication)
로그인
서비스의 사용자임을 아이디, 패스워드 등을 통해서 인증받는다.

인가 (Authorization)
인증받은 사용자가 서비스의 기능을 사용할 때 허가해주는 것
로그인이 유지되는 상태에서 일어나는 일

Session

사용자가 서버에 로그인 되어있음이 지속되는 상태

  1. 사용자가 로그인에 성공하면 서버는 Session ID를 생성해서 메모리(하드디스크, 데이터베이스 등..)에 저장한다.
  2. 서버로부터 받은 Session ID는 브라우저에 쿠키로 저장된다.
  3. 사용자가 요청을 보낼때 마다 브라우저는 Session ID를 서버에 함께 보내고, 서버는 받은 Session ID를 사용하여 해당 사용자의 세션 정보를 찾아낸다.

단점

  • 사용자가 동시에 많이 접속을 하면 메모리가 부족해진다.
  • 서버가 꺼지면 메모리는 모두 사라지기 때문에 위험하다.
  • 메모리가 아닌 하드디스크 또는 데이터베이스에 넣으면 안되나??
    • 메모리보다 속도가 느리다.
  • 서비스의 규모가 커서 서버가 여러 대 있는 경우
    • 1번 서버에서 로그인을 하고 2번 서버에서 기능 요청 하는 경우, 2번 서버에는 로그인을 할 때 생성된 Session ID가 없으므로 문제가 발생한다.
    • 사용자의 요청이 각자 할당된 서버로만 보내지게 하는 것은 어렵다.
      메모리형 데이터베이스 (ex. redis)를 통해 관리하기도 한다.

JWT (Json Web Token)

Session의 단점을 해결하기 위해 나온 '토큰 방식'

  1. 사용자가 로그인에 성공하면 서버는 토큰을 생성하고 브라우저에 전달한다. 서버에는 아무것도 저장하지 않는다.

토큰은 header, payload, verify signature 3부분으로 구성된다.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

{
  "alg": "HS256",
  "typ": "JWT"
}

alg
Verify Siganature 값을 만드는데 사용되는 알고리즘
한쪽 방향으로만 계산이 가능하다. -> 서버의 비밀 값을 알 수가 없다.
typ
토큰의 타입, 항상 "JWT" 이다.

Payload

  • base64로 디코딩하면 아래와 같이 json 형식의 데이터가 들어있다.
    • base64는 너무 보안에 취약하지 않나? -> 그래서 Header와 Verify Signature가 있다.
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
  • Claim: 토큰에 담긴 사용자 정보 등의 데이터
    • 누가 누구에게 발급했는지,
    • 토큰의 유효 기간
    • 서비스가 사용자에게 이 토큰을 통해 공개하기 원하는 내용 (닉네임, 관리자 여부 등)

이후 요청마다 사용자로부터 서버에 보내진다.
서버가 요청마다 데이터베이스에서 찾을 필요가 없다.

Verify Signature (서명)

  • Header, Payload, 서버의 비밀 키 3개를 Header의 암호화 알고리즘에 넣으면 나온다.
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  your-256-bit-secret
)
  • 서버에 요청이 들어오면 Header, Payload 값을 서버의 비밀 키와 함께 돌려봐서 계산된 결과값이 Verify Signature 값과 일치하는지 확인한다.
  • 계산 값과 Verify Signature 값이 일치하고 유효기간도 지나지 않았다면 사용자는 로그인된 회원으로서 인가를 받는다.
  • 시간에 따라 바뀌는 상태값을 가지지 않는것을 stateless 하다고 한다. 반대로 session은 stateful 하다.

단점

  • session과 같이 모든 사용자의 상태를 기억하고 있다면 기억하는 대상의 상태들을 언제든 제어할 수 있다.

    • 예를 들어 PC에서 로그인한 상태의 사용자가 모바일에서 또 로그인하면 PC에서 로그아웃 되도록 기존 세션을 종료 할 수 있다.
  • 발급한 토큰을 다시 뺐어오거나, 탈취당한 토큰을 무효화하는 방법은 없다. 따라서 실서비스 중에 jwt 만으로 인가를 구현하는 곳은 많지 않다.

보완하기 위한 방법

만료시간을 가깝게 잡아서 토큰의 수명을 짧게 한다.

수명이 몇 시간이나 몇 분 이하로 짧은 access 토큰과, 2주 정도의 긴 refresh token 2개를 발급한다.

  1. access token 과 refresh token 발급 후 클라이언트에게 발급
  2. refresh token 값은 데이터베이스에 저장
  3. 사용자는 access token의 기간이 끝나면 refresh token을 보낸다.
  4. 서버는 refresh token을 비교하고, 맞다면 새로운 access token을 발급한다.

refresh token만 데이터베이스에서 안전하게 관리하고, refresh token이 탈취되면 데이터베이스에서 해당 token의 정보를 지워버린다.

but! access token이 유효한 동안은 바로 차단할 방법이 없다.

세션 VS. 토큰! JWT가 뭔가요?

1개의 댓글

comment-user-thumbnail
2023년 7월 17일

정말 유익한 글이었습니다.

답글 달기