[네트워크] Cookie, Session, JWT
Updated: Categories: CS여러가지 인증 전략에 대해 알아보자
Cookie
- Stateless한 HTTP의 단점을 해소하고자 사용
- 브라우저에 저장되어있는 key-value 형태의 데이터
- 브라우저가 종료되어도 쿠키는 유지됨
- expire 시간을 설정할 수 있음
- 브라우저에 총 300개의 쿠키 저장 가능
- 하나의 도메인당 20개 저장 가능
- 쿠키 하나당 4KB까지 저장 가능
- 응답 HTTP에 Set-Cookie 헤더를 추가하면 쿠키를 만들 수 있음
- 브라우저에서 자동으로 요청 HTTP 헤더에 쿠키를 추가함
구성 요소
- 이름(Name) : 각각의 쿠키를 구별하는 데 사용되는 이름
- 값(Value) : 쿠키의 이름과 관련된 값
- 유효시간(Expires) : 쿠키의 유지시간
- 도메인(Domain): 쿠키를 전송할 도메인
- 경로(Path): 쿠키를 전송할 요청 경로
Local/Session Storage
- HTML5에서 추가된 브라우저 저장소
- 하나의 도메인에서 하나의 로컬 스토리지를 가짐
- 브라우저에서 요청할때 HTTP 헤더에 자동으로 쿠키를 추가하는데…
- 만약 필요없는 정보까지 저장되어 쿠키 용량이 커진다면 요청의 크기가 계속 커지게 됨
- 따라서 굳이 보낼 필요없는 데이터는 Local Storage 및 Session Storage에 저장함
- Local Storage는 영구저장, Session Storage는 브라우저가 꺼지면 삭제됨
단점
- 용량이 작음 (최대 4KB)
- 매 HTTP 요청마다 포함되어 데이터가 커질경우 서버에 부담을 줌
- 평문으로 되어있어 보안에 취약함
Session
- 쿠키를 사용하며, 사용자 정보를 서버에서 관리하는 방식
- 쿠키를 사용하므로 만료시간 설정 가능
- 브라우저가 종료되면 세션이 만료됨
동작원리
- 클라이언트 인증요청
- 서버에서 세션ID 발급 -> 저장소에 세션ID와 사용자 데이터를 저장
- 발급한 세션ID를 쿠키에 담아 응답
- 클라이언트는 세션ID가 담긴 쿠키를 헤더에 담아 서버에 요청
- 서버는 세션ID를 보고 세션저장소에서 찾음
- 세션ID에 매핑된 사용자 데이터를 조회하고 응답
장점
- 사용자 정보를 클라이언트에 저장해야하는 단일 쿠키 방식보다 보안에 유리함
- 쿠키에는 세션ID만 저장하기때문에 탈취당해도 타격없음
단점
- 사용자가 많아질수록 서버 메모리를 많이 차지함
- 접속시마다 세션을 발급하고, 계속 관리해함
- 동접자가 많아질수록 서버에 과부하를 일으킴
세션 분리
- 만약 세션정보를 서버 인메모리로 관리한다고 했을때 서버를 껐다 키면?
- 사용자의 세션정보는 브라우저 쿠키에 저장되어 있지만…
- 서버에서 해당 세션이 유실되어서 다시 발급해야함
- 세션 저장소의 위치를 서버와 분리에 외부에 둠
- 세션을 인메모리가 아닌 외부 스토리지에 저장한다 (보통 가벼운 인메모리 DB를 사용. Redis)
Session Cluster
- 세션 저장소가 만약 하나라면 해당 저장소에 문제가 발생했을 때 모든 세션이 날아가게됨
- 따라서 세션 저장소를 물리적으로 여러개 두고, 모두가 동일한 상태를 유지하도록 함 (일관성)
- Sticky Connection(동일한 사용자가 발생시킨 요청은 동일한 WAS에서 처리됨을 보장) 제약에서 자유로움
JWT (Json Web Token)
- 사용자 정보를 암호화시킨 토큰에 저장하는 방법
- URL-Safe 텍스트로 구성되기 때문에 HTTP 프로토콜의 어느 위치에든 들어갈 수 있음
- 보통 HTTP 헤더에 넣음
- json 포맷을 사용하여 데이터를 저장
구성요소
- Base64 Url-Safe 방식으로 인코딩
- dot(.)을 구분자로 결합함
- Header, Payload, Signature 세 부분으로 구성됨
- Header
- Header는 두가지 종류의 key값을 가진다
typ
: 토큰 타입alg
: 암호화 알고리즘 방식 / Signature에 사용 (HMAC, RSA 지원)
- Header는 두가지 종류의 key값을 가진다
- Payload
- JWT를 통해 전달하고자 하는 데이터, Claim-Set 이라고 함
- JWT 자체는 암호화된것이 아닌 인코딩된것이므로 민감정보를 포함하면 안된다.
- 세가지 종류의 Claim으로 구분된다
- Public Claims : 사용자 정의 클레임 / 공개용 정보를 저장 (충돌 방지를 위해 URI 포맷 사용)
- Private Claims : 사용자 정의 클레임 / 사용자 정보를 저장
- Registered Claims : 미리 등록된 클레임 / 필수적으로 사용할 필요는 없지만 사용을 권고함
iss
: 토큰을 발급한 발급자 (Issuer)exp
: 만료시간이 지난 토큰은 사용불가nbf
: Not Before의 의미로 해당 시간 이전에는 토큰 사용불가iat
: 토큰이 발급된 시각jti
: JWT ID로 토큰에 대한 식별자
- Signature
- 토큰이 위변조되지 않았음을 증명함
- Header 인코딩값 + Payload 인코딩값 -> 비밀키(secret)으로 해싱 -> base64 인코딩
동작원리
- 클라이언트 인증요청
- 서버에서 요청 검증 후 JWT 반환
- 사용자의 브라우저에서 해당 JWT를 저장하고 매 요청시마다 HTTP 헤더에 JWT를 넣어서 보냄
- 서버는 매번 JWT 유효성 검사 후 요청 수락
장점
- Stateless 상태를 지향하는 Rest API에서 적합
- 클라이언트가 정보를 가지고 있기에 세션처럼 별도의 저장소가 필요하지 않음
단점
- 세션보다는 보안 취약
- 세션이 탈취당하면? : 해당 세션을 삭제해버리면 됨
- JWT가 탈취당하면? : JWT 유효기간이 끝날때까지 사용가능
- 따라서 유효기간을 짧게주고 Refresh Token을 사용한다.
- 다중 로그인 컨트롤, 사용자 유효성 체크, 강제 로그아웃 기능 구현이 어려움