Contents

1. 왜 이 개념들이 중요한가?

2. HTTP는 Stateless하다

3. 쿠키

4. 세션

5. 토큰

6. JWT

7. Access Token, Refresh Token, ID Token

8. 저장 위치

9. 로그아웃과 토큰 무효화

10. 보안 이슈


1. 왜 이 개념들이 중요한가?

SSO 서비스는 여러 서비스의 인증 흐름을 하나로 연결하는 역할을 한다.

이때 핵심은 다음 두 가지다.

  1. 사용자의 로그인 상태를 어떻게 유지할 것인가?
  2. 인증/인가 결과를 여러 서비스에 어떻게 안전하게 전달할 것인가?

이 문제를 해결하기 위해 쿠키, 세션, 토큰, JWT가 사용된다.

쿠키: 브라우저에 값을 저장하고 요청에 함께 보내는 수단
세션: 서버가 사용자의 로그인 상태를 저장하는 방식
토큰: 인증/인가 결과를 표현하는 값
JWT: 토큰을 JSON 형태로 표현하고 서명한 형식

즉, 이 개념들은 각각 따로 떨어진 기술이 아니라 로그인 상태 유지와 인증 정보 전달을 위한 구성 요소다.


2. HTTP는 Stateless하다

HTTP는 기본적으로 이전 요청 상태를 기억하지 않는다.

1번째 요청: 로그인 요청
2번째 요청: 마이페이지 요청

서버 입장에서는 두 요청이 같은 사용자의 요청인지 기본적으로 알 수 없다.

따라서 로그인 이후에도 사용자를 계속 식별하려면 별도의 상태 관리 방식이 필요하다. 이때 사용하는 대표적인 방식이 쿠키와 세션이다.


3. 쿠키

3.1 쿠키란?

서버가 브라우저에 저장하도록 내려주는 작은 데이터

서버가 응답에 Set-Cookie 헤더를 담아 보내면, 브라우저는 쿠키를 저장한다.
이후 같은 조건의 요청을 보낼 때 브라우저가 쿠키를 자동으로 함께 전송한다.

서버 → 브라우저: Set-Cookie
브라우저 → 서버: Cookie

쿠키는 세션 ID, 사용자 설정, 로그인 유지 정보 등을 저장하는 데 사용된다. 브라우저에 저장되는 작은 데이터이며, 세션 식별자나 사용자 설정을 저장하는 데 자주 사용된다.

3.2 역할

브라우저가 상태 값을 들고 있다가 요청마다 자동으로 보내준다

그래서 로그인 상태 유지에 자주 사용된다.

  • 다만 쿠키 자체가 로그인 상태를 의미하는 것은 아니다.
  • 쿠키 안에 무엇을 담느냐에 따라 역할이 달라진다.
세션 ID를 담으면 → 세션 기반 인증
JWT를 담으면 → 토큰 기반 인증
사용자 설정을 담으면 → 사용자 환경 유지

3.3 주요 옵션

HttpOnly:

  • JavaScript에서 쿠키에 접근하지 못하게 한다.
  • XSS로 쿠키 값이 직접 탈취되는 위험을 줄인다.

Secure:

  • HTTPS 연결에서만 쿠키를 전송한다.

SameSite:

  • 다른 사이트에서 온 요청에 쿠키를 보낼지 제어한다.
  • CSRF 방어에 도움을 준다.

Domain:

  • 쿠키가 적용될 도메인 범위를 정한다.
  • SSO에서 같은 Root Domain 쿠키 공유와 관련 있다.

Path:

  • 쿠키가 적용될 URL 경로를 정한다.

Max-Age / Expires:

  • 쿠키 만료 시간을 정한다.

3.4 SSO에서 쿠키의 역할

SSO에서는 쿠키가 매우 중요하다.

예를 들어 사용자가 IdP에서 로그인하면, IdP는 사용자의 로그인 상태를 유지하기 위해 SSO Session을 만들고, 그 세션을 식별할 값을 쿠키로 내려줄 수 있다.

사용자 → IdP 로그인
IdP → SSO Session 생성
IdP → 브라우저에 세션 쿠키 전달

이후 사용자가 다른 서비스에 접근하면, 해당 서비스는 사용자를 다시 IdP로 보낸다.
IdP는 브라우저가 보낸 쿠키를 보고 이미 로그인된 사용자임을 확인한다.

서비스 B 접근
→ IdP로 리다이렉트
→ IdP가 쿠키 확인
→ SSO Session 있음
→ 로그인 화면 생략

즉, SSO에서 쿠키는 IdP가 사용자의 로그인 상태를 기억하는 수단으로 사용될 수 있다.


4. 세션

4.1 세션이란?

서버가 사용자의 로그인 상태를 저장하는 방식

사용자가 로그인하면 서버는 세션 저장소에 사용자 정보를 저장하고, 클라이언트에는 세션을 찾을 수 있는 세션 ID만 전달한다.

서버 저장소:
sessionId → 사용자 정보

세션 기반 인증은 로그인 시 생성된 세션 ID를 통해 사용자의 세션을 식별하고, 일반적으로 이 세션 ID가 브라우저 쿠키에 저장되어 요청마다 서버로 전달된다.

4.2 세션 인증 흐름

  1. 사용자가 로그인한다.
  2. 서버가 사용자 정보를 검증한다.
  3. 서버가 세션을 생성한다.
  4. 서버가 세션 ID를 쿠키로 내려준다.
  5. 브라우저는 이후 요청마다 세션 ID 쿠키를 보낸다.
  6. 서버는 세션 ID로 세션 저장소를 조회한다.
  7. 세션이 유효하면 로그인된 사용자로 처리한다.
  • 로그인 상태는 서버가 저장한다.
  • 브라우저는 세션 ID만 들고 다닌다.

4.3 쿠키와 세션의 관계

세션은 서버에 저장되는 로그인 상태이고, 쿠키는 그 세션을 식별하기 위한 세션 ID를 브라우저가 들고 다니는 수단

쿠키와 세션은 경쟁 관계가 아니다.

세션 방식에서도 보통 쿠키를 사용한다.
다만 쿠키에 사용자 정보를 직접 저장하는 것이 아니라, 서버 세션을 찾기 위한 세션 ID를 저장한다.

쿠키:
브라우저가 값을 저장하고 요청에 보내는 수단
 
세션:
서버가 로그인 상태를 저장하는 방식
 
세션 ID:
브라우저와 서버 세션을 연결하는 식별자

5. 토큰

5.1 토큰이란?

인증 또는 인가 결과를 나타내는 값

사용자가 인증에 성공하면 서버는 토큰을 발급하고, 클라이언트는 이후 요청에 토큰을 함께 보낸다.

사용자 로그인
→ 서버가 토큰 발급
→ 클라이언트가 토큰 저장
→ 요청마다 토큰 전달
→ 서버가 토큰 검증

토큰은 사용자의 신원과 권한을 나타내는 데이터이며, 인증 서버가 발급하고 이후 보호된 리소스 접근 요청에 포함된다.

5.2 토큰은 왜 쓰는가?

인증/인가 결과를 여러 시스템에 전달하기 좋다.

특히 SSO에서는 사용자가 인증 서버에서 로그인한 뒤, 그 인증 결과를 여러 서비스가 신뢰해야 한다.

인증 서버 → 토큰 발급
서비스 A → 토큰 검증
서비스 B → 토큰 검증
서비스 C → 토큰 검증

즉, 토큰은 SSO에서 인증 결과를 전달하고 검증하기 위한 수단으로 사용된다.

5.3 세션 ID와 토큰의 차이

세션 ID도 넓게 보면 사용자를 식별하기 위한 값이다.
하지만 일반적으로 “토큰 기반 인증”이라고 할 때는 Access Token, Refresh Token, ID Token, JWT 같은 구조를 말한다.

차이는 다음과 같다.

세션 ID:
서버 세션 저장소를 조회하기 위한 식별자
 
토큰:
인증/인가 결과를 표현하고 전달하는 값

세션 ID는 보통 그 자체만으로 사용자 정보를 알 수 없다.
서버가 세션 저장소를 조회해야 한다.

반면 JWT 같은 토큰은 토큰 안에 사용자 식별자, 권한, 만료 시간 같은 정보를 담을 수 있다.


6. JWT

6.1 JWT란?

JSON Web Token의 약자로, JSON 형태의 정보를 담고 서명한 토큰 형식이다.

서버는 JWT의 서명을 검증해서 토큰이 위조되지 않았는지 확인한다.

JWT = JSON 기반 Claim + 서명

JWT는 JSON 객체로 정보를 안전하게 전달하기 위한 표준이며, 디지털 서명을 통해 위변조 여부를 확인할 수 있다.

6.2 JWT 구조

JWT는 세 부분으로 구성된다.

Header.Payload.Signature

Header:

  • 토큰 타입, 서명 알고리즘

Payload:

  • 사용자 식별자, 권한, 만료 시간 등 Claim

Signature:

  • Header와 Payload가 위조되지 않았는지 검증하기 위한 서명

6.3 JWT는 암호화가 아니라 서명이다

JWT의 Payload는 암호화된 것이 아니라 Base64Url로 인코딩된 것이다.
따라서 누구나 내용을 확인할 수 있다.

JWT Payload는 숨겨진 정보가 아니다.

그래서 JWT에는 민감한 정보를 넣으면 안 된다.

넣어도 되는 정보:
사용자 식별자
권한
만료 시간
발급자
 
넣으면 안 되는 정보:
비밀번호
주민등록번호
전화번호
민감한 개인정보

JWT의 서명은 내용을 숨기는 용도가 아니라, 토큰이 위조되지 않았는지 확인하는 용도다.

6.4 장점

서버가 매 요청마다 세션 저장소를 조회하지 않아도 된다.

서버는 토큰의 서명을 검증하고, Payload의 Claim을 확인해서 사용자를 식별할 수 있다.

세션 방식:
세션 ID 확인 → 세션 저장소 조회
 
JWT 방식:
토큰 서명 검증 → Claim 확인
  1. 서버가 세션 상태를 저장하지 않아도 된다.
  2. 여러 서버로 확장할 때 세션 공유 부담이 줄어든다.
  3. 웹, 모바일, API 환경에서 사용하기 좋다.
  4. 인증 서버가 발급한 토큰을 여러 서비스가 검증할 수 있다.

6.5 단점

한 번 발급된 토큰을 즉시 무효화하기 어렵다는 점이다.

서버가 토큰 상태를 저장하지 않고 서명과 만료 시간만 검증한다면, 로그아웃을 해도 이미 발급된 Access Token은 만료 전까지 사용할 수 있다.

만료 전 Access Token을 즉시 폐기하기 어렵다.

또한 토큰이 탈취되면 만료 전까지 악용될 수 있다.

그래서 보통 다음 전략을 함께 사용한다.

1. Access Token 만료 시간을 짧게 설정
2. Refresh Token을 서버에 저장
3. Refresh Token Rotation 적용
4. 로그아웃 시 Refresh Token 무효화
5. 필요하면 Access Token 블랙리스트 사용

7. Access Token, Refresh Token, ID Token

7.1 Access Token

리소스 서버에 접근할 권한을 증명하는 토큰

Access Token:
이 사용자가 이 API에 접근할 권한이 있는가?

API 요청에 사용된다.

GET /api/users/me
Authorization: Bearer access-token

Access Token은 탈취 시 위험하기 때문에 보통 짧은 만료 시간을 가진다.

7.2 Refresh Token

Access Token이 만료되었을 때 새 Access Token을 발급받기 위한 토큰

Refresh Token:
새 Access Token을 발급받기 위한 토큰

Access Token보다 오래 살아있기 때문에 더 안전하게 관리해야 한다.

보통 다음 방식으로 관리한다.

1. HttpOnly Cookie에 저장
2. 서버 DB 또는 Redis에 저장
3. 재발급 요청 시 서버 저장값과 비교
4. 재발급 시 Refresh Token도 새로 발급

7.3 ID Token

OIDC에서 사용자의 신원을 확인하기 위한 토큰

ID Token:
이 사용자는 누구인가?

클라이언트가 사용자의 인증 결과를 확인하는 데 사용한다.

Access Token과 목적이 다르다.

ID Token:
사용자 신원 확인
 
Access Token:
리소스 접근 권한 확인

7.4 세 토큰의 차이

ID Token:
사용자가 누구인지 확인하기 위한 토큰
 
Access Token:
리소스 서버/API에 접근하기 위한 토큰
 
Refresh Token:
Access Token을 재발급받기 위한 토큰

8. 저장 위치

토큰은 어디에 저장하느냐에 따라 보안 특성이 달라진다.

8.1 LocalStorage

장점:

  • 구현이 단순하다.
  • 새로고침해도 유지된다.

단점:

  • JavaScript로 접근 가능하다.
  • XSS 공격에 취약하다.

장점:

  • HttpOnly 설정이 가능하다.
  • 브라우저가 요청에 자동으로 포함한다.

단점:

  • 자동 전송 특성 때문에 CSRF를 고려해야 한다.

쿠키를 사용할 때는 보통 다음 옵션을 함께 사용한다.

  • HttpOnly
  • Secure
  • SameSite

8.3 Memory

장점:

  • JavaScript 전역 저장소나 브라우저 저장소에 남지 않는다.
  • 탭을 닫거나 새로고침하면 사라질 수 있어 탈취 위험이 줄어든다.

단점:

  • 새로고침 시 토큰 유지가 어렵다.

9. 로그아웃과 토큰 무효화

9.1 세션 기반 로그아웃

세션 방식에서는 서버 세션을 삭제하면 된다.

1. 서버 세션 삭제
2. 브라우저의 세션 쿠키 삭제

세션 상태를 서버가 관리하기 때문에 로그아웃 처리가 비교적 명확하다.

9.2 JWT 기반 로그아웃

서버가 상태를 저장하지 않는 방식으로 운영될 수 있기 때문에 로그아웃이 더 까다롭다.

클라이언트에서 토큰을 삭제하더라도, 이미 발급된 Access Token 자체가 서버에서 바로 사라지는 것은 아니다.

그래서 보통 다음 방식으로 처리한다.

  1. 클라이언트 메모리에 저장된 Access Token 삭제
  2. 서버 저장소(DB/Redis)에 저장된 Refresh Token 삭제
  3. 브라우저의 Refresh Token 쿠키를 만료시켜 클라이언트 측 Refresh Token 제거
  4. 이미 발급된 Access Token은 짧은 만료 시간으로 대응
  5. 필요 시 Access Token 블랙리스트 사용

9.3 SSO 로그아웃

SSO에서는 로그아웃 시 하나의 서비스만 보면 안 된다.

고려해야 할 대상이 여러 개다.

  1. IdP의 SSO Session
  2. 각 SP의 서비스 세션
  3. Refresh Token
  4. 이미 발급된 Access Token

따라서 SSO 로그아웃은 다음 흐름으로 이해하면 좋다.

사용자 로그아웃
→ IdP의 SSO Session 종료
→ 현재 서비스 세션 종료
→ 필요 시 다른 서비스에 로그아웃 전파
→ Refresh Token 무효화
→ Access Token은 짧은 만료 시간 또는 블랙리스트로 대응

10. 보안 이슈

10.1 XSS

공격자가 악성 스크립트를 사용자의 브라우저에서 실행시키는 공격

LocalStorage에 Access Token을 저장하면 JavaScript로 토큰을 읽을 수 있기 때문에 탈취 위험이 있다.

대응 방법은 다음과 같다.

  1. HttpOnly Cookie 사용
  2. 입력값 검증
  3. 출력 인코딩
  4. CSP 적용
  5. 토큰에 민감 정보 저장 금지

HttpOnly Cookie는 XSS 자체를 막는 것은 아니지만, JavaScript로 쿠키 값을 직접 읽지 못하게 하여 토큰 탈취 위험을 줄인다.

10.2 CSRF

사용자가 로그인된 상태를 이용해 원치 않는 요청을 보내게 만드는 공격

쿠키는 브라우저가 자동으로 요청에 포함하기 때문에 CSRF를 고려해야 한다.

대응 방법은 다음과 같다.

  1. SameSite 설정
  2. CSRF Token 사용
  3. 중요한 요청은 추가 검증
  4. Origin / Referer 검증

CSRF는 쿠키가 자동 전송되는 특성을 악용하므로, 인증 쿠키를 사용하는 구조에서는 SameSite, CSRF Token, Origin/Referer 검증을 함께 고려해야 한다.

10.3 Redirect URI 조작

OIDC/OAuth2 흐름에서는 Redirect URI 검증이 중요하다.

공격자가 Redirect URI를 조작하면 Authorization Code나 토큰이 공격자 쪽으로 전달될 수 있다.

대응 방법은 다음과 같다.

  1. 등록된 Redirect URI만 허용
  2. 와일드카드 Redirect URI 지양
  3. state 파라미터 검증
  4. PKCE 적용