[네트워크] 쿠키 (Cookie) & 세션 (Session) & 토큰 (Token, JWT)

전윤혁·2024년 8월 2일

Networks

목록 보기
5/6

클라이언트 인증

세션, 쿠키, 토큰서버가 클라이언트를 인증하기 위해 사용된다.

https://velog.io/@airoca/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTPHypertext-Transfer-Protocol-%ED%8A%B9%EC%A7%95-HTTP-%EB%A9%94%EC%8B%9C%EC%A7%80

이전 글에서, HTTP 프로토콜이 비연결성(Connectionless)무상태성(Stateless)을 가진다고 설명했다. 짧게 다시 설명하면, HTTP는 클라이언트와 서버의 연결을 유지하지 않고, 서버는 클라이언트의 상태 정보를 저장하지 않는다.

그런데 실제로 웹사이트를 이용하면, 로그인 정보 등의 클라이언트 상태 정보가 어딘가에 저장되어, 페이지를 이동하더라도 로그인 상태가 유지된다는 것을 알 수 있다. 이러한 상태 관리가 세션, 쿠키, 토큰을 통해 이루어지는 것이다.

🍪 쿠키 (Cookie)

쿠키(Cookie)는 브라우저에 저장되는 작은 데이터 조각이다.

서버가 클라이언트에 대한 정보를 저장하지 않기에, 정보를 저장하는 역할을 클라이언트에게 맡긴 형태로 볼 수 있다. 쿠키는 아래와 같은 특징들을 지닌다.

1) 쿠키의 특징

  • 사용자의 웹 브라우저에 Key-Value 쌍 형태로 저장된다.

  • 특정 도메인 및 경로에 대해 유효하며, 해당 조건을 만족하는 요청에만 포함된다.
    (유효한 도메인의 경우, 브라우저가 자동으로 Request Header에 쿠키를 포함시켜 요청을 전송한다.)

  • 쿠키는 만료 날짜를 설정할 수 있으며, 만료 날짜가 지나면 자동으로 삭제된다.
    (날짜가 남아있는 경우 브라우저를 닫더라도 인증이 유지된다.)

  • HTTP 메시지의 Response Header에 Set-Cookie 속성을 사용하면 클라이언트에 쿠키를 만들 수 있다.

  • 쿠키는 여러 공격들(공유 PC, XSS, CSRF 등)로 인해 탈취될 수 있다는 보안상 취약점이 있기에, 민감한 정보를 저장하는 용도로는 적합하지 않다.

  • 쿠키 사용 시, 개인화된 서비스가 가능하다는 장점이 있다.

2) 쿠키의 종류

  • 세션 쿠키 (Session Cookies)
    브라우저가 닫힐 때 삭제된다. 사용자 세션을 유지하는 데 사용된다.

  • 영구 쿠키 (Persistent Cookies)
    만료 날짜가 설정되어 있으며, 브라우저가 닫혀도 삭제되지 않고 만료 날짜까지 유지된다.

  • 서드파티 쿠키 (Third-Party Cookies)
    사용자가 방문한 도메인이 아닌 다른 도메인에서 설정한 쿠키이며, 주로 광고 및 트래킹 목적으로 사용된다.

📌 서드파티 쿠키(Third-Party Cookies)란?

쿠키의 종류 중 서드파티 쿠키는 다소 이질적으로 느껴질 수 있다. 서드 파티 쿠키란 사용자가 방문한 웹사이트에 웹사이트 소유자가 아닌 제 3자가 해당 웹사이트에서 사용자의 행태를 기록, 추적하는 것이다. 이에 따라, 서드파티 쿠키에 포함될 수 있는 정보는 개인정보가 아닌 정보로 제한된다.

그렇다면 서드파티 쿠키는 왜 사용되는가? 예를 들어, 쇼핑몰에서 구경했던 상품이 다른 사이트에서도 지속적으로 광고로 표시되었던 경험이 있을 것이다. 이렇듯, 기업은 고객이 웹사이트를 돌아다니며 열람했던 물건들에 대한 정보들을 서드파트 쿠키를 통해 모으는 것이다.

3) 쿠키의 내용

  • Name: 쿠키의 식별자 이름

  • Value: 쿠키가 저장하는 데이터

  • Domain: 쿠키가 유효한 도메인

  • Path: 쿠키가 유효한 경로

  • Expiration Date: 쿠키의 유효 기간

  • Security: 쿠키가 전송될 때 보안 상태를 지정
    (Secure 속성이 설정된 경우, 쿠키는 HTTPS 프로토콜을 통해서만 전송된다.)

  • HttpOnly: 쿠키에 JavaScript를 통해 접근할 수 없도록 설정
    (이 속성이 설정되면, 클라이언트 측 스크립트에서 쿠키를 읽을 수 없다.)

📌 Secure & HttpOnly

위의 두 속성은 각각 다른 유형의 공격을 예방하는 데 중요한 역할을 한다.

  • Secure 속성은 쿠키가 오직 HTTPS 프로토콜을 통해서만 전송되도록 제한하여, 네트워크 상에서의 중간자 공격(MITM)이나 데이터 스니핑을 방지한다. 즉, 악의적인 제3자가 쿠키를 가로채는 것을 막아 보안을 강화한다.
  • HttpOnly 속성은 클라이언트 측 스크립트(예: JavaScript)가 쿠키에 접근하지 못하게 하여, 크로스사이트 스크립팅(XSS) 공격으로 인한 쿠키 탈취를 방지한다. 이는 웹 페이지의 스크립트가 쿠키를 조작하거나 훔치는 것을 차단한다.

✅ 세션 (Session)

세션은 각 사용자에 대한 고유한 식별값을 통해 클라이언트를 식별하고, 연결을 유지하는 방식이다.

세션은 쿠키를 기반으로 동작하지만, 사용자의 정보를 브라우저 대신 서버의 메모리에 저장하는 방식이다. 이를 위해 각 사용자에 대한 고유한 식별값인 Session ID를 사용한다.

📌 세션(Session)의 정의

세션을 생성한다, 유지한다 등의 표현을 읽을 때마다 용어의 의미가 모호하다는 생각이 들 수 있다. 세션은 로그인 여부 등 사용자와 서버의 관계가 기억되어 보존되고 있는 상태를 말한다.

1) 세션을 사용한 인증 과정

  1. 사용자가 로그인을 시도하면, 서버 측에서는 회원 DB를 통해 유효한 사용자가 맞는지 확인한다. (그림의 1~2)

  2. 유효한 사용자인 경우, 서버는 세션을 생성하고, 세션 저장소를 통해 Session ID를 발급한 후 Response 헤더에 Session ID를 포함시켜 응답한다 (그림의 3~5)

  3. 사용자는 Session ID를 쿠키로 저장하여, 이후 데이터 요청을 진행할 때 자동으로 Request 헤더에 포함시켜 함께 전송한다. (그림의 6)

  4. 서버는 요청을 받은 경우, Session ID의 유효성을 검사한 후, 유효할 경우 요청된 데이터를 반환한다. (그림의 7~9)

2) 세션의 특징

  • 세션 데이터는 서버의 메모리, 데이터베이스, 또는 파일 시스템에 저장된다.

  • 서버에 데이터가 저장되는 방식이기에, 사용자가 많아질수록 서버 메모리를 많이 차지하게 되며 성능 저하로 이어질 수 있다.

  • 세션은 일정 시간 동안 비활성 상태이거나, 사용자가 명시적으로 로그아웃할 때 종료된다. 세션 만료 시간은 서버 측에서 설정할 수 있다.

  • 세션 데이터는 서버 측에서만 접근 가능하므로, 쿠키보다 보안 측면에서 우수하다.
    (따라서 세션은 로그인 등 민감한 작업을 수행할 때 사용된다.)

📌 왜 세션이 쿠키보다 보안이 우수한가?

다음과 같은 의문이 생길 수 있다.

"어차피 Session ID도 클라이언트 측에 쿠키로 저장되는데, Session ID가 탈취될 경우 사용자 데이터가 털리는건 똑같잖아?"

쿠키 대신 세션 인증을 사용하면, 클라이언트 측에서 세션 데이터를 직접 접근하거나 변경할 수 없기에 보안이 낫다고 할 수 있다.

만약 암호화되지 않은 쿠키가 탈취되었다고 가정해보자. 만약 쿠키를 사용하여 인증하였을 경우, 사용자의 아이디나 패스워드 정보가 그대로 유출될 수 있다. 하지만 세션 인증에서는 Session ID만 탈취될 수 있으며, 이는 사용자 데이터를 직접 포함하지 않기 때문에 정보 노출 위험이 상대적으로 적다는 뜻이다.

물론, 공격자가 Session ID를 탈취한 경우 해당 세션 사용자로 위조할 수 있고, 이를 세션 하이재킹(Session Hijacking) 이라고 한다. 하지만 대부분의 클라이언트-서버 통신은 SSL/TLS 암호화를 통해 보호된다.


🪙 토큰 (Token, JWT)

토큰(Token)은 상태 저장 없이도 유효성을 확인할 수 있는 데이터 조각이다.

앞선 설명에서, 세션 인증 방식은 쿠키에 비해 보안적으로 우수하지만, 서버에 세션 데이터를 저장함에 따라 사용자가 많아지면 서버에 부하가 걸린다는 점을 언급하였다.

토큰은 서버가 클라이언트의 상태 정보를 직접 저장하지 않고도 클라이언트를 인증하고 권한을 부여할 수 있는 방법을 제공한다. 어떻게 저장 데이터와 대조 없이 인증을 수행할 수 있는 것일까? 이는 토큰의 구조를 통해 알 수 있다.

1) 토큰의 구조 (JWT 구조)

토큰의 구조는 JWT(Json Web Token)의 구조를 통해 설명하겠다. JWT는 가장 널리 사용되는 토큰 형식으로, 인증에 필요한 정보들을 암호화시킨 JSON 토큰이다.

위의 그림에서 볼 수 있듯이, JWT는 Header, Payload, Signature 세 부분으로 구성된 JSON 객체이고, 각각의 부분은 점(.)으로 구분된다. 또한, 각 부분은 Base64 URL-safe Encode 인코딩을 사용하여 인코딩된다.

Header는 JWT의 유형과 서명 알고리즘을 정의한다. 일반적으로 두 가지 요소로 구성된다.

{
  "alg": "HS256",
  "typ": "JWT"
}
  • alg: 사용된 서명 알고리즘 (HS256, RS256 등)
  • typ: 토큰의 유형, 보통 JWT로 설정됨

위의 JSON 객체는 Base64Url로 인코딩되어 JWT의 첫 번째 부분을 형성한다.

Payload

Payload는 토큰에 담을 클레임(Claims)들을 포함하고 있다. 여기서 클레임이란 key-value 쌍으로 이루어진, JWT를 통해 실제로 알 수 있는 데이터이다. 즉, 실제로 서버와 클라이언트 간 주고받는 정보가 포함되어 있다.

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
  • sub: 사용자 ID
  • name: 사용자 이름
  • iat: 토큰 발행 시간

Signature

Signature는 토큰의 무결성을 검증하기 위해 사용된다. HeaderPayload를 각각 Base64Url로 인코딩 후 연결한 후, 헤더에서 선언한 알고리즘서버의 유일한 key를 이용해 암호화가 진행된 값이다.

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

예시에서는 연결된 문자열을 해싱 알고리즘(HMAC SHA256)과 서버의 유일한 비밀 키(secret)를 사용하여 암호화한다.

Header와 Payload는 단순히 인코딩 된 값으로, 제 3자가 복호화가 가능하지만, Signature의 경우 서버의 유일한 비밀키가 유출되지 않는 이상 복호화가 불가능하다.

서버로부터 JWT를 받은 클라이언트는, 서버로 다시 요청을 보낼 때마다 받은 JWT를 그대로 전송한다. 서버는 요청을 수신하면 JWT를 세 부분으로 분리하고, 해당 토큰의 Header, Payload, 그리고 서버의 유일한 비밀 키로 다시 Signature를 생성한다.

이 때 클라이언트가 보낸 Signature와 서버가 재생성한 Signature를 비교하여 두 값이 일치하면, 토큰의 무결성(Integrity)을 확인할 수 있다. 이렇게 서버는 토큰의 위변조 여부를 검증하고, 저장 데이터와 대조할 필요 없이 페이로드의 정보를 바탕으로 클라이언트를 인증하고 권한을 부여할 수 있다.

📌 무결성(Integrity)이란?

무결성은 데이터가 저장되거나 전송되는 동안 변조되지 않고 원래의 상태(정확성, 일관성, 유효성)를 유지하는 특성을 의미한다.

2) 토큰을 사용한 인증 과정

  1. 사용자가 로그인을 시도하면, 서버 측에서는 회원 DB를 통해 유효한 사용자가 맞는지 확인한다. (그림의 1~2)

  2. 유효한 사용자인 경우, 서버는 Access Token(JWT)를 발급한 후, Access Token을 Response 헤더에 포함시켜 응답한다. (그림의 3~4)

  3. 사용자는 Access Token을 쿠키로 저장하여, 이후 데이터 요청을 진행할 때 자동으로 Request 헤더에 포함시켜 함께 전송한다. (그림의 5)

  4. 서버는 요청을 받은 경우, Access Token의 무결성을 검증하고, 유효한 토큰일 경우 요청된 데이터를 반환한다. (그림의 6~7)


마치며

실제로 많이 사용되는 인증 방식은 JWT 기반 방식이다.
다음 글에서는 JWT의 인증 방식을 Access Token과 Refresh Token으로 나누어 보다 구체적으로 살펴보고, 실제로 Spring Boot에서 JWT 기반 로그인을 구현한 예제를 살펴보도록 하자.

profile
전공/개발 지식 정리

0개의 댓글