쿠키(Cookie)와 세션(Session)
HTTP 프로토콜 특징
클라이언트 서버 구조
- 클라이언트가 서버에 요청(request)을 보내면, 서버는 그에 대한 응답(response)를 보냄
비연결 지향(Connectionless)
- 클라이언트의 요청에 응답한 후에는 연결을 끊음(연결 유지 X)
- 최소한의 자원으로 서버 유지
무상태(Stateless)
- 연결을 끊는 순간 클라이언트와 서버의 통신이 끝나고, 서버는 클라이언트의 상태 정보를 보존하지 않음
- 클라이언트가 요청할 때 필요한 데이터를 추가적으로 담아서 전송해야 함
- 항상 같은 서버를 유지하지 않아도 됨
- 응답 서버를 쉽게 바꿀 수 있어서 서버 확장성이 높음(무한한 서버 증설 가능)
쿠키와 세션의 필요성
- HTTP 프로토콜의 특징으로 모든 요청 간에는 의존관계가 없음
- 현재 접속한 사용자가 이전에 접속했던 사용자와 같은 사용자인지 아닌지 알 수 있는 방법 존재 X
- 통신할 때마다 새로 연결하기 때문에 클라이언트는 매 요청마다 인증을 해야 함
- 로그인을 진행한 후, 다른 서비스를 사용하기 위해 매번 로그인(인증)을 하는 상황 발생
- 클라이언트의 상태 정보를 유지할 필요가 있을 경우,
쿠키
와세션
을 활용해서 Stateful한 동작 구현 가능- 무상태를 지향하기 위해 매 요청마다 필요한 정보를 담아 서버와 통신하는 경우, 비용과 부하가 커질 수 있음
쿠키(Cookie)
- 개념
- 클라이언트 로컬에 저장되는 키와 값이 들어있는 파일
- 사용자 인증이 유효한 시간 명시 가능(유효시간이 정해지면 브라우저가 종료되어도 인증 유지)
- 클라이언트의 상태 정보를 브라우저(로컬)에 저장하여 참조
- 구성 요소
- 쿠키의 이름(name)
- 쿠키의 값(value)
- 쿠키의 유효시간(Expires)
- 쿠키를 전송할 도메인 이름(Domain)
- 쿠키를 전송할 요청 경로(Path)
- 동작 방식
- 웹브라우저가 서버에 요청
- 상태를 유지하고 싶은 값을 쿠키(cookie)로 생성
- 서버가 응답할 때 HTTP 헤더(Set-Cookie)에 쿠키를 포함해서 전송
- 전달받은 쿠키는 웹 브라우저가 관리, 다음 요청 때 쿠키를 HTTP 헤더에 자동으로 넣어서 전송
- 서버에서 쿠키 정보를 읽어 이전 상태 정보를 확인 후 응답
- 사용 예
- 아이디, 비밀번호 저장
- 쇼핑몰 장바구니
세션(Session)
- 개념
- 일정 시간 동안 같은 브라우저로부터 들어오는 요청을 하나의 상태로 보고 그 상태를 유지함
- 웹 브라우저를 통해 서버에 접속한 이후부터 브라우저를 종료할 때까지 유지되는 상태
쿠키
를 사용하여 값을 주고 받으며 클라이언트의 상태 정보를 유지함- 사용자 정보 파일을 쿠키는 브라우저에 저장하고, 세션은 서버측에서 관리
- 사용자에 대한 정보를 서버에 두기 때문에, 사용자가 많아질수록 서버 메모리 많이 차지
- 보안 면에서 쿠키보다 우수
- 쿠키는 클라이언트 측에서 쉽게 탈취 가능
- 쿠키는 클라이언트 측에서 변경이 가능한 반면, 세션은 서버에서만 변경 가능
- 세션ID값 탈취는 적극적인 해킹공격으로 쿠키보다 어려움
- 쿠키는 클라이언트 측에서 쉽게 탈취 가능
- 일정 시간 동안 같은 브라우저로부터 들어오는 요청을 하나의 상태로 보고 그 상태를 유지함
- 동작 방식
- 웹브라우저가 서버에 요청
- 서버가 해당 웹브라우저(클라이언트)에 유일한 ID(Session ID)를 부여함
- 서버가 응답할 때 HTTP 헤더(Set-Cookie)에 Session ID를 포함해서 전송
- 웹브라우저는 부여된 Session ID를 쿠키에 저장해두고, 다음 요청 때마다 해당 쿠키를 HTTP 헤더에 넣어서 전송
- 서버는 Session ID를 확인하고, 해당 세션에 관련된 정보를 확인한 후 응답
- 로그인을 하는 경우, 해당 Session ID의 로그인 상태를 유효한 값으로 바꿔 저장
- 이후 요청에서 해당 Session ID를 가진 클라이언트는 로그인 상태가 유효하므로 별도의 로그인 없이 서비스 이용 가능
- 사용 예
- 로그인
다중 서버 환경에서 세션 관리
서버를 다중화했을 경우, 세션 불일치 이슈 발생
- Sticky Session (스티키 세션)
- 클라이언트의 요청이 항상 해당 클라이언트의 세션이 저장된 서버로만 전달됨
- 로드밸런서에서 요청 쿠키(Session ID)를 읽고 지정된 서버(세션이 있는)로만 요청을 전달함
- 세션 정보가 없을 경우, 로드밸런서의 기본 알고리즘대로 요청 전달
- 클라이언트의 요청이 항상 해당 클라이언트의 세션이 저장된 서버로만 전달됨
- Session Clustering (세션 클러스터링)
- 클러스터링: 병렬 처리해서 여러 대의 서버를 하나의 서버처럼 운영
- 세션을 서버 각각에 복사해서 모든 서버가 모든 세션을 보유하고 있음
- 특정 서버에서 세션이 생성될 때 다른 서버로 세션을 전파하여 복제
- Session Storage (세션 스토리지)
- 세션만 관리하는 별도의 DB 서버를 두고, 모든 서버가 해당 서버를 참조함
토근 기반 인증 방식
- 세션은 사용자의 수 만큼 서버 메모리를 차지하기 때문에, 최근에는 이를 보완하는 토근 기반의 인증방식을 많이 사용함(
stateless
) - ex)
JWT(JSON Web Token)
쿠키와 세션의 차이
쿠키 | 세션 | |
---|---|---|
저장 위치 | 클라이언트의 웹 브라우저가 지정하는 메모리 or 하드디스크 | 서버 메모리 |
저장 형식 | Text | Object |
만료 시점 | 쿠키 저장 시 설정 | 정확한 시점 알 수 없음 |
보안 | 클라이언트에 저장되므로 취약 | Session ID만 저장하고, 이 값에 따라 서버에서 처리하므로 비교적 보안성 좋음 |
속도 | 클라이언트에 저장되어 서버에 요청 시 빠름 | 정보가 서버에 저장되어 있어 서버 처리가 필요해 쿠키보다 느림 |
용량 제한 | 한 도메인 당 20개, 한 쿠키당 4KB | 제한없음 |
➕ 토큰
- 개념
- 메모리 공간을 많이 차지하는 세션 방식의 대안으로 사용자에게
세션 아이디
대신토큰
을 발급
- 메모리 공간을 많이 차지하는 세션 방식의 대안으로 사용자에게
- 동작 방식
- 클라이언트가 서버에 접속 시, 서버는 클라이언트에게 인증되었다는 의미로
토큰
부여 (해당 토큰은 유일함)- 클라이언트는 전달받은 토큰을 쿠키나 스토리지에 저장함
- 토큰을 발급받은 클라이언트는 다시 서버에 요청을 보낼 때 헤더에 토큰을 심어보냄
- 서버의 토큰 일치여부 체크로 인증과정 처리
- 클라이언트로부터 받은 토큰과 서버에서 제공한 토큰의 일치여부 체크
- 클라이언트가 서버에 접속 시, 서버는 클라이언트에게 인증되었다는 의미로
- 특징
- 적은 서버의 부담
- 토큰은 클라이언트에 저장 됨 → 세션을 관리했던 서버의 부담을 덜 수 있음
- 해당 서버만이 만들 수 있는 토큰 발급 → 상태를 저장하지 않고도 사용자의 정보 파악 가능
- 적은 서버의 부담
- 한계
- 한 번 발행한 토큰은 유효기간 만료시 까지 통제 불가
- 여러 기기에서 로그인 제한 불가
- 세션에 비해 토큰 정보 탈취 당할 가능성 높음
- 해결 방법으로
만료 시간
이용
- 해결 방법으로
- 토큰 자체 데이터 길이가 긺
- 인증 요청이 많아질 수록 네트워크 부하가 심해짐
- 한 번 발행한 토큰은 유효기간 만료시 까지 통제 불가
JWT (JSON Web Token)
- 개념
- 인증에 필요한 정보들을
암호화
시킨 JSON 토큰 - JWT토큰을 HTTP 헤더에 실어 서버가 클라이언트를 식별하는 방식
- 인증에 필요한 정보들을
- 특징
- JWT는 JSON 데이터를 Base64 URL-safe_Encode를 통해 인코딩을 직렬화한 것
Self-contained
- 필요한 정보를 자체적으로 지니고 있음
Signature
- 전자서명을 통한 위변조 체크
- 토큰 내부에 위변조 방지를 위해 개인키를 통한 전자서명이 들어감
- 사용자가 JWT를 서버로 전송시 서버는 서명을 검정하는 과정을 거침
- 검증 완료 시 요청한 응답을 돌려줌
Calim
- JSON 데이터 구조로 표현한 토큰
- 표준규약(RFC-7519)에 따라 생성된 암호화된 문자열(토큰)
URL-safe
- 두 개체 사이에서 손쉽게 전달되며, 사용되는 JSON 데이터는 URL에 포함될 수 있는 문자만으로 생성
- HMAC 알고리즘 사용으로 비밀키 또는 RSA를 이용한 Public Key / Private Key 쌍으로 서명 가능
-
구조
.
을 구분자로 나누어지는 세가지 문자열의 조합Header
- 알고리즘과 토큰 타입을 포함
- "alg" : 정보를 암호화할 해싱 알고리즘 지정
- "typ" : 토큰의 타입 지정
Payload
- 토큰에 저장할 정보를 가짐
- Claim형태(key, value로 이루어진 한쌍의 정보)로 이루어짐
- Registered Claim
- 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기위하여 이름이 이미 정해진 클레임
- 해당 클레임의 사용은 전부 선택적
- Public Claim
- 충돌이 방지된 이름을 가지고 있어야함
- 충돌을 방지하기 위해 클레임 이름을 URI형식으로 생성
- Private Claim
- 서버와 클라이언트, 서비스와 서비스간에 협의하에 사용되는 클레임
- 공개 클레임과 달리 이름이 중복되어 충돌 발생 가능
- 민감한 정보는 불포함 또는 암호화 처리가 필요
- Registered Claim
Signature
- 인코딩된 Header와 Payload를 더한 뒤 비밀키로 해싱하여 생성
- 토큰의 위변조 여부 확인 시 사용
- Header 및 Payload는 단순 인코딩된 값으로 해커가 복호화와 조작 가능
- Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상 복호화할 수 없음
- 토큰 인증 과정
클라이언트
가 서버로 로그인 요청을 보냄서버
는 검증 후 클라이언트 고유 ID등의 정보를 Payload에 담고, 암호화할 비밀키를 사용해 Access Token(JWT) 발급클라이언트
는 전달받은 토큰을 저장해두고, 서버에 요청할 때마다 토큰을 요청 헤더 Authorization에 포함시켜 함께 전달서버
는 토큰의 Signature 을 비밀키로 복호화한 다음, 위변조 여부 및 유효 기간 등을 확인 후 유효한 토큰이라면 요청에 응답
AccessToken
- 클라이언트에서 요청한 로그인이 성공한 경우, 서버는 AccessTocken 발급
- 사용자
- 발급받은 토큰 정보를 기억하고 있음
- 서버 호출시 헤더에 해당 토큰을 담아 호출
- 서버
- AccessToken을 DB나 파일에 저장하지 않았으므로 미리 정의된 비밀키를 이용해 비교하여 인증 처리
이와 같은 이유로 서버는 특정 사용자의 접속을 강제로 만료시키기 어려움
- AccessToken을 DB나 파일에 저장하지 않았으므로 미리 정의된 비밀키를 이용해 비교하여 인증 처리
RefreshToken
- 개념
- 한번 발급되면 만료기간까지 계속 사용가능하므로 탈취시 위험하다는 단점을 해결하기 위해 사용
- Access Token, Refresh Token으로 이중으로 나누어 인증 진행
- Access Token의 유효기간을 짧게 만들고, 유효기간이 만료될 때마다 Refresh Token을 통해 새로운 Access Token을 만듦
- 특징
- 클라이언트에서 로그인을 요청을 하고 성공을 할 경우, 기존 AccessToken 외에 추가로 RefreshToken을 발급
- AccessToken 에 비해 긴 만료시간을 갖도록 설정
- 클라이언트 측
- AccessToken이 만료되었을 시 추가로 받았던 RefreshToken을 사용하여 재발급 요청 진행
- 서버 측
- 유효한 RefreshToken이 오면 추가로 AccessToken 과 RefreshToken을 다시 발급
- RefreshToken의 경우 서버 Storage에 따로 저장하며 이후 검증에 사용
- 이로인해 추가적인 I/O작업 필요하며 이는 별도의 I/O작업이 없다는 JWT의 빠른 인증처리의 특징에 상반되는 부분임
- 장점
- 토큰이 탈취되더라도 제한된 기간만 접근 가능
- RefreshToken에 대한 만료 강제 설정 가능
- 단점
- 클라이언트는 AccessToken 만료시 갱신하는 로직을 구현해야 함
- 서버는 별도의 storage 필요
Ref
1. JWT 토큰 인증과 (쿠키, 세션, 토큰) (opens in a new tab)
JWT(Json Web Token) 소개 및 활용 (opens in a new tab)