3 minute read

세션기반 인증 (Session-based Authentication)

HTTP 프로토콜은 무상태성(Stateless)과 비연결성(Connectless)과 같은 특징을 가진다. 이런 특징으로 인해 HTTP 프로토콜을 따르는 통신 방식에서는 로그인 후 다시 웹페이지에 접근하면 로그인 상태가 유지되지 않는다는 문제점이 있다. 이를 해결하기 위해 등장한 것이 쿠키(Cookie)와 세션(Sessrion)을 이용한 세션 기반 인증방식 이다.


_PsLhwyFA-1618305417398

사용자가 웹사이트에서 아이디 및 비밀번호를 가지고 로그인을 시도하면 어떤 방식으로 작동하는지 살펴보자

  1. 사용자가 Id와 Password 등 필요한 정보를 가지고 서버에 요청을 보낸다
  2. 서버는 요청이 들어오면 로그인 정보에 대한 유효성 검증을 한다. => 검증을 마치면 사용자에 대한 정보를 고유한 id를 기준으로 서버에 저장한다.
    • 여기서 말하는 서버의 저장공간이 세션 스토어고, 고유 id값으로 저장되는 정보를 세션이라 한다.
  3. 서버는 응답헤더를 통해 세션id를 포함해 요청에 대한 응답을 반환한다.
  4. 응답을 받은 클라이언트는 해당 세션 id를 클라이언트 내에 저장한다.
    • 이때 사용된 클라이언트 내의 저장 공간이 쿠키이다.
  5. 사용자는 인증이 필요한 요청에 접근할 때마다 세션 id가 담긴 쿠키를 요청 헤더에 포함시켜 요청을 보내고
  6. 서버는 세션 스토어에 일치하는 세션 id가 있는지 검증한 후
  7. 세션 id가 유효하면 요청에 해당하는 데이터를 반환한다.


로그아웃은 어떻게 구현할까. 세션 id가 담긴 쿠키는 클라이언트에 저장되어 있고, 서버는 세션을 저장하고 있다. 로그아웃은 두 곳에 저장된 데이터를 삭제하는 방식으로 구현할 수 있다.

  1. 서버의 세션 정보를 삭제해야 한다.
  2. 클라이언트의 쿠키를 갱신해야 한다.

서버가 클라이언트의 쿠키를 임의로 삭제할 수는 없다. 대신 set-cokie로 세션 id의 키값을 무효한 값으로 갱신해야 한다.

쿠키가 어떤 데이터를 갖고 있는지는 링크를 통해 반드시 확인하고 넘어가자.



토큰 기반 인증 (Token-based Authentication)

토큰 기반 인증은 세션 기반 인증과 다르게 토큰을 이용해 인증을 하는 방식이다. 마찬가지로 로그인 flow를 통해 알아보자.

  1. 사용자가 Id와 Password 등 필요한 정보를 가지고 서버에 요청을 보낸다.
  2. 서버는 요청이 들어오면 로그인 정보에 대한 유효성을 검증한다. => 검증을 마치면 정상적으로 발급된 토큰임을 증명하는 signature를 갖는 토큰을 생성한다.
  3. 서버는 응답 시 생성된 토큰을 클라이언트에 반환한다.
  4. 응답받은 클라이언트는 해당 토큰을 쿠키 등에 저장하고, 요청시에 요청 헤더에 토큰을 담아 서버로 요청을 보낸다.
  5. 서버는 토큰의 유효성을 검증해 데이터를 반환한다.

서버에서 상태 정보를 저장하는 세션 기반 인증과 다르게 토큰 기반 인증은 서버에서 상태 정보를 저장하고 있지 않는다. 토큰 자체가 유효한 토큰인지 아닌지만 검증하기 때문에 서버에 부하를 주지 않는다는 장점을 가진다. 클라이언트는 새로운 요청을 보낼때마다 토큰을 헤더에 포함시키기만 하면 되고 서버는 이를 해독할 수 있는지만 판단하면 되기 때문에 확장성 측면에서도 큰 장점을 가진다.


JWT(JSON Web Token)

JWT(JSON Web Token)는 이런 토큰을 JSON형식을 이용해 웹에서 사용할 수 있는 엑세스 토큰을 다루는 표준이다. JWT는 토큰 기반 인증 방식으로 토큰 자체에 유저 정보를 담아서 HTTP 헤더로 전달하기 때문에 세션을 유지할 필요가 없고 가볍게 데이터를 주고받을 수 있다는 장점이 있다.


기본 구조

bjTILbPyY-1607412302702

Part Description
Header - 데이터의 타입 - 알고리즘 종류
Payload(Claims) - 실제 어떤 데이터가 담겨 있는지(암호화가 안되어있어 웹으로 노출하면 안되는 데이터를 담아서는 안된다)
- 가능한 많은 데이터를 담지 않는 것이 좋다. - Production으로 사용 할 시에는 토큰이 언제까지 유효한지 담는 것이 좋음
Signature - 데이터와 토큰이 위변조 되지 않았음을 증명
- 데이터를 일정하게 해싱하고 해싱한 데이터를 암호화 해서 데이터가 위변조 되지 않음을 증명
- HMAC-SHA256 사용 (해당 알고리즘을 사용하기 위해 비밀키를 생성하는데 비밀키는 반드시 노출이 되지 않도록 조심해야 한다)


1. Header

Header는 어떤 종류의 토큰인지, 어떤 알고리즘으로 암호화 할 지가 적혀있다.

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

이 JSON 객체를 base64방식으로 인코딩하면 JWT의 헤더가 완성된다.


2.Payload

실제 토큰으로 사용하려는 데이터가 담겨있다. 각 데이터를 Claim이라 하며 3종류로 나뉜다.


Reserved claims(등록된 클레임) : 이미 예약된 Claim으로 필수는 아니지만 사용하길 권장합니다. key 는 모두 3자리 String입니다.

  • 모든 이름이 짧은데, JWT를 최대한 작게 만드려는 디자인 원칙에 맞춘 것입니다.
  • iss: 토큰 발급자 (issuer)
  • sub: 토큰 제목 (subject)
  • aud: 토큰 대상자 (audience)
  • exp: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야 합니다.
  • nbf: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.
  • iat: 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있습니다.
  • jti: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용합니다.


Public claims(공개 클레임) : 사용자 정의 Claim.

  • Public 이라는 이름처럼 공개용 정보입니다.
  • 충돌 방지를 위해 URI 포맷을 이용해 저장합니다.


Private claims(비공개 클레임) : 사용자 정의 Claim

  • Public claims 과 다르게 사용자가 임의로 정한 정보입니다.
  • 일반 정보를 저장합니다.


{
  "sub": "someInformation",
  "name": "phillip",
  "iat": 151623391
}

헤더와 마찬가지로 JSON 객체 형태를 base64로 인코딩 하면 페이로드가 완성된다.


3. Signature

Header와 Payload의 데이터 무결성과 변조 방지를 위한 서명이 담겨있다. 예를들어 HMAC SHA256 알고리즘을 사용하면 다음과 같은 방식으로 생성된다.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)