[Web] Session & Cookie & Token(JWT)

장유진·2023년 7월 19일
0

Web Development

목록 보기
1/5

HTTP의 무상태성 Stateless

HTTP는 무상태(Stateless) 프로토콜을 사용합니다. 서버가 클라이언트의 상태를 보존하지 않으며 모든 요청이 독립적으로 다뤄집니다. 따라서 요청을 할 때마다 사용자가 누군지 서버에 알려주어야 합니다.

이를 위한 대표적인 방식이 바로 세션과 토큰입니다.

세션(Session) & 쿠키(Cookie)

세션(Session)

‘사용자가 웹 브라우저를 통해 웹 서버에 접속한 시점으로부터 웹 브라우저를 종료하여 연결을 끝내는 시점까지 같은 사용자로부터 오는 일련의 요청을 하나의 상태로 보고 그 상태를 일정하게 유지하는 기술’

즉, 서버와 클라이언트 간의 연결이 활성화 된 상태. 세션 ID를 사용해서 사용자의 로그인이 지속되는 상태.

  • 세션에 대한 모든 정보는 세션 저장소(세션 DB)에 저장되어 있습니다. 인증된 사용자에 대한 정보를 서버에서 관리하고 있기 때문에 Stateful 하다고 할 수 있습니다.
  • 세션 저장소로 Redis와 MemCached와 같은 메모리형 데이터베이스 서버에서 관리할 수 있습니다.

쿠키(Cookie)

  • 쿠키는 특정 도메인 내에서만 유효합니다. (도메인 단위로 관리됩니다.)
  • 유효기간이 존재하며, 4kb 정도의 용량 제약이 있습니다.
  • 인증 정보 뿐 아니라 여러가지 정보를 저장할 수 있습니다.
  • 사이트를 방문하면 브라우저는 서버에 요청을 보내 필요한 데이터를 받아옵니다. 이 때 받아오는 Response에 쿠키가 포함되고, 해당 서버에 요청을 할 때마다 요청과 함께 쿠키를 자동으로 전송합니다.
    • 쿠키는 세션 ID를 전달하기 위한 매개체로 기능합니다.

세션 기반 인증 방식

  1. 사용자 로그인 요청
  2. 서버는 유저 DB에서 사용자를 확인하고, 세션 저장소에 사용자 정보 세션을 생성
  3. 세션 저장소의 ID(세션 ID)를 쿠키를 통해 클라이언트에게 전송
  4. 페이지 이동 등 서버로 요청을 할 때마다 요청과 함께 저장된 쿠키를 클라이언트가 서버로 다시 전송
  5. 서버가 쿠키에 담긴 세션 ID와 세션 저장소의 세션 ID를 대조해서 인증 여부 판단

세션 기반 인증 방식의 장점과 단점

실제 데이터는 서버 - 세션 저장소에서 관리되고, 쿠키로는 참조될 내용(세션 ID)만 실리기 때문에 보안면에서 상대적으로 안전합니다. 만약 세션 ID가 탈취당한 경우에라도 서버에서 해당 세션을 무효화 할 수 있습니다.

매 요청 시마다 서버가 세션 저장소에서 세션 ID를 조회하는 과정이 필요하고, 사용자가 많으면 많을 수록 서버에 대한 비용이 커진다는 단점을 가지고 있습니다. 또 Stateful하다는 특징 때문에 확장성이 떨어질 수 있습니다.

JWT(JSON Web Token)

토큰(Token)

토큰은 Base64로 인코딩 또는 암호화된 3가지 데이터를 이어붙인 것으로 다음과 같은 구성을 가지고 있습니다.

Header 헤더

{ 
   "alg": "HS256",
   "typ": JWT
 }
  • type - header의 타입은 항상 JWT 입니다.
  • alg - 알고리즘의 약자로 서명을 만드는데 필요한 알고리즘을 지정합니다. HS256등 여러 방식 중 하나를 지정 할 수 있습니다.

Payload 내용

토큰에 담긴 사용자 정보 등의 데이터를 클레임(Claim)이라고 합니다. 클레임은 JSON 형식으로 이루어져 있으며 등록된 클레임(Registered Claim), 공개 클레임(Public Claim), 비공개 클레임(Private Claim) 세 가지의 종류가 있습니다.

등록된 클레임(Registered Claim)

누가 누구에게 발급했는지, 이 토큰이 언제까지 유효한지 등 토큰 정보를 전달하기 위한 클레임으로, 등록된 클레임의 사용은 모두 선택적(Optional)으로 사용 가능합니다. 표준 스펙으로 이름이 정의된 7가지는 다음과 같습니다.

1. iss (Issuer) : 토큰 발급자
2. sub (Subject) : 토큰 제목
3. aud (Audience) : 토큰 대상자
4. exp (Expiration Time) : 토큰 만료 시간 - 시간은 NumericDate 형식으로 되어있어야 합니다.
5. nbf (Not Before) : 토큰 활성 날짜 - 해당 날짜 이전에는 토큰이 활성화 되지 않습니다.
6. iat (Issued At) : 토큰 발급 시간
7. jti (JWT Id) : JWT 토큰 식별자

공개 클레임(Public Claim)

사용자 정의 클레임, 충돌 방지를 위해 클레임 이름을 URI 형식으로 작성합니다. 공개되어도 안전한 정보들을 공개 클레임으로 정의합니다.

{
    "http://example.com/is_root": true
}

비공개 클레임(Private Claim)

사용자 정의 클레임, 클라이언트와 서버에서 협의된 클레임으로 미리 약속한 방식으로 사용해야 합니다. 비공개 클레임을 작성할 때 다른 클레임과 이름이 충돌하지 않도록 주의합니다.

{
  "iss": "https://auth.example.com", // 등록된 클레임
  "exp": 1677836800, // 등록된 클레임 
  "https://example.com/is_root": true, // 공개 클레임
  "username": "geniee1220", // 비공개 클레임
  "email": "geniee1220@example.com", // 비공개 클레임
}

Verify Signiture 서명

  • 헤더와 페이로드, 그리고 서버에서만 가지고 있는 Secret key를 헤더에서 지정한 알고리즘으로 암호화 하면 서명(시그니처) 값이 생성됩니다.
  • 서버는 서명을 Secret Key로 복호화하여 토큰의 조작 여부를 검증할 수 있습니다.
  • https://jwt.io/

토큰 기반 인증 방식

  1. 사용자 로그인 요청
  2. 서버는 사용자 정보를 확인하고, 클라이언트에게 JWT 토큰을 생성하여 전달
  3. 클라이언트는 받은 JWT 토큰을 저장하고 이후 요청에는 헤더나 쿠키에 JWT 토큰을 포함하여 서버에 전송
  4. 서버는 받은 JWT 토큰의 유효성을 검사하고, JWT 토큰에 포함된 사용자 정보에 권한이 있는지 확인

토큰 기반 인증 방식의 장점과 단점

Stateless하게 관리되기 때문에 서버의 비용이 줄어들고, 확장성이 좋다는 특징이 있습니다. 예를 들면, 세션을 서버측에 저장하고 여러 대의 서버를 사용하여 요청을 분산한 경우, 각 서버는 로그인 된 사용자의 세션 상태를 공유하지 않습니다. 따라서 로그인한 사용자는 처음 로그인한 서버에만 요청을 보내야합니다. 그러나 토큰을 사용하는 경우, 서버 간에 세션 정보를 공유할 필요가 없기 때문에 어떤 서버로 요청이 들어오더라도 문제가 발생하지 않습니다.

토큰을 서버에서 추적하는 게 아니기 때문에 탈취 당했을 때 무효화 할 수 있는 방법이 없습니다. 원론적으로 토큰 기반 방식에서는 세션 기반 방식처럼 강제 로그아웃 기능을 지원하지 않습니다.

액세스 토큰(Access Token)과 리프레쉬 토큰(Refresh Token)

로그인 시 수명이 몇 시간이나 몇 분 이하로 짧은 액세스 토큰(Access Token)과 비교적 길게, 대체로 2주 정도로 잡혀있는 리프레쉬 토큰(Refresh Token) 2개를 발급하는 방식. 토큰 기반 인증 방식의 단점을 보완하고자 나온 방법 중 하나입니다.

  1. 사용자 로그인 요청
  2. 서버는 사용자 정보를 확인하고 토큰을 생성. 리프레쉬 토큰은 상응값을 DB에도 저장하고 클라이언트에게 액세스 토큰과 리프레쉬 토큰을 전송.
  3. 클라이언트는 리프레쉬 토큰을 저장하고 이후 요청마다 액세스 토큰을 헤더에 실어 전송
  4. 실려온 액세스 토큰이 만약 만료된 토큰이라면, 서버는 권한 없음 에러를 클라이언트에게 반환
  5. 클라이언트는 리프레쉬 토큰을 함께 서버로 전송
  6. 서버는 클라이언트에게 받은 리프레쉬 토큰을 DB에 저장한 값(2)과 비교해서 검증한 후 새로운 액세스 토큰을 클라이언트에게 전송

❗️액세스 토큰의 등록된 클레임에 유효기간이 명시되어 있기 때문에, 프론트엔드 단에서 4번 과정을 생략하고 바로 재발급 요청을 할 수 있습니다.

리프레쉬 토큰이 유효할 동안은 액세스 토큰이 만료될 때마다 다시 로그인 할 필요 없이 새로 발급을 받을 수 있습니다. 탈취가 된다고 하더라도 리프레쉬 토큰을 DB에서 삭제, 갱신이 되지 않게 하는 방식으로 강제 로그아웃을 시킬 수 있습니다. 단, 액세스 토큰이 살아있는 동안 바로 차단을 할 수 없다는 점이 한계점으로 꼽힙니다.

토큰 기반 인증 방식에서 반드시 고려해야 할 점

민감한 정보를 유저 정보에 실어보내지 않기

JWT는 변환(디코딩)이 매우 쉽기 때문에 비밀번호나 신용카드 번호 등 민감한 유저 정보들을 토큰에 포함하면 절대 안 됩니다.

JWT 탈취

Http Only Cookie 를 설정하면 XSS 공격을 방지할 수 있습니다.

❗️XSS(Cross Site Scripting)는 서버 측에서 제공되는 Script가 아닌 권한이 없는 사용자가 웹사이트에 Script를 삽입하여 의도치 않은 동작을 일으키는 공격을 말합니다.

리프레쉬 토큰 자체가 탈취될 가능성도 있기 때문에 Refresh Token Rotation 도 필요합니다.

JWT None Algorithm Attack

None Algorithm Attack은 Header의 Algorithm을 None으로 변조하여 인증을 우회하는 공격입니다.

alg을 “none”으로 입력했을 때 서버에서 제대로 거부하고 있는지 확인해야 합니다.

Bruteforce Attack

서명 검증에 사용하는 Secret Key를 쉽고 간단한 값으로 지정하면 무작위 대입 공격에 뚫릴 수 있습니다.

생성용 키 private key / 검증용 키 public key 2개를 사용하거나 복잡도가 높은 키를 사용해야 합니다.



Reference

⓵ JWT란 무엇인가? 그리고 어떻게 사용하는가? (1) - 개념
https://velog.io/@vamos_eon/JWT란-무엇인가-그리고-어떻게-사용하는가-1
⓶ [Web] 쿠키(Cookie)와 세션(Session)의 차이, 쿠키란? 세션이란?
https://code-lab1.tistory.com/298
⓷ [Web] HTTP Only와 Secure Cookie 이해하기 https://nsinc.tistory.com/121
⓸ Access Token의 문제점과 Refresh Token https://hudi.blog/refresh-token/
⓹ JWT에서 Refresh Token은 왜 필요한가?
https://velog.io/@park2348190/JWT에서-Refresh-Token은-왜-필요한가
⓺ JWT(Json Web Token) 알아가기 https://brunch.co.kr/@jinyoungchoi95/1
⓻ 서버 인증 방식(세션/쿠키, 토큰) https://velog.io/@kingth/서버-인증-방식세션쿠키-토큰
⓼ 세션 VS. 토큰! JWT가 뭔가요? https://www.youtube.com/watch?v=1QiOXWEbqYQ
⓽ 우아한 테크 [10분 테코톡] 🎡토니의 인증과 인가 https://youtu.be/y0xMXlOAfss
⓾ JWT(Json Web Token)란 무엇인가!! https://velog.io/@ye-ji/JWTJson-Web-Token에서-정보빼기

0개의 댓글