개발자들이 인증 관련 처리를 하다 보면 세션, 쿠키, 토큰, JWT 등의 단어들을 맞닥뜨리게 된다. 이 단어들의 각각 의미가 무엇이며, 인증처리 간의 어떻게 연결되어 사용될 수 있는지 알아보자.
쿠키 vs 토큰?
인증처리를 할 때 가장 많이 하는 질문 중 하나이다. '인증 처리를 쿠키로 하는 것이 좋은가요? 아니면 토큰 방식이 좋은가요?' 사실 이 질문은 쿠키에 대한 지식이 부족하기 때문에 하는 질문 중 하나이다.
우선 쿠키에 대해 우선 알아보자.
쿠키란
우리가 사이트에 방문하면 브라우저는 서버에 요청(Request)을 보낸다.
서버는 요청에 대한 응답(Response) 보내는데 데이터와 페이지 정보 등을 전달하게 된다. 또한 브라우저에 저장할 쿠키도 전달하게 된다. 그러면 브라우저는 해당 쿠키를 저장하고 있다가 요청을 보낼 때 함께 보내게 된다.
주의할 점은 쿠키는 도메인에 따라 제한된다는 점이다. 예를 들어 유튜브에서 준 쿠키는 유튜브에만 보내진다. 또한 쿠키는 유효기간을 정할 수 있고, 인증뿐 아니라 여러 가지 정보를 저장할 수 있다. (다국어처리를 위한 언어설정 정보 등..)
보시다시피 쿠키는 그저 서버와 브라우저간에 데이터를 전송하기 위한 매개체로 이용된다.
쿠키 전송 방식
- Set-Cookie : 서버에서 클라이언트로 쿠키 전달(응답)
- Cookie : 클라이언트가 서버에서 받은 쿠키를 저장하고, HTTP 요청 시 서버로 전달
set-cookie: sessionId=abcde1234; expires=Set, 26-Dec-2023 00:00:00 GMT; path=/;
domain=.google.com; Secure
쿠키는 인증(로그인 세션 및 토큰 관리) 및 광고 정보 트래킹, 다국어 설정 등의 사용된다. 브라우저에 쿠키가 저장되어 있으면 항상 서버로 전송된다.
그렇기 때문에 네트워크 트래픽을 추가 유발될 수 있고 최소한의 정보만 사용(세션 ID, 인증 토큰)하는 것이 좋다. 만약 서버에 전송하고 싶지 않다면, 웹 브라우저 내부에 데이터를 저장하는 웹 스토리지(LocalStorage, SessionStorage)를 이용하면 된다.
주의할 점으로 보안에 민감한 정보는 저장하지 않는다. (패스워드, 주민번호 등)
생명주기(Expires, max-age)
Set-Cookie: expires=Sat, 26-Dec-2020 04:39:21 GMT
- 만료일이 되면 쿠키를 삭제한다.
Set-Cookie: max-age=3600 (3600초를 의미)
- 쿠기가 유지되는 시간(초)을 정의하며, 이 값은 현재 시간에서 더해져서 쿠키의 만료 시간이 계산된다.
- 정해진 만료시간이 되면 쿠기가 삭제된다.
만약 두 설정을 다 지정하지 않는다면 세션 쿠기(Session Cookie)라고 하며, 브라우저가 종료시 까지만 유지를 한다. max-age 나 Expires 설정을 하면 영속 쿠키가 되며 브라우저 종료 시점이 아닌 만료날짜 기준으로 유지가 된다. 두 설정을 함께 설정한 다음 우선순위는 max-age에 있다.
도메인설정 (domain)
domain=example.org
도메인을 명시하면 명시한 기준 도메인과 서브 도메인까지 포함되어 쿠키가 전달된다.
- domain=example.org를 지정해서 쿠키를 생성
- example.org 인 기준 도메인과 dev.example.org 같은 서브 도메인도 쿠키가 접근할 수 있다.
도메인을 생략한다면 현재 문서 기준 도메인만 적용이 된다.
- example.org 에서 쿠키를 생성하고 domain 설정을 생략
- example.org에서는 쿠기가 접근이 가능하다 dev.example.org 같은 서브 도메인은 쿠키가 접근 불가능 하다.
경로 (path)
path=/home
path=/
경로를 지정하면 이 경로를 포함한 하위 경로 페이지만 쿠키가 접근한다. 일반적으로 path=/ 루트로 지정하며 전 페이지에 대응한다.
보안 (Secure, HttpOnly, SamSite)
- Secure
- 쿠키는 http, https를 구분하지 않고 전송
- Secure를 적용하면 https인 경우에만 전송
- HttpOnly
- XSS 공격 방지
- 자바스크립트에서 접근 불가(document.cookie)
- HTTP 전송에만 사용
- SameSite
- XSRF 공격 방지
- 요청 도메인과 쿠키에 설정된 도메인이 같은 경우만 쿠키 전송한다.
세션과 토큰?
토큰은 쿠키와 비교하는 것이 아닌 세션과 비교가 이루어져야 한다. 그럼 왜 세션과 토큰이 필요한지 알아보자.
HTTP는 웹 사이트를 이용할 때 쓰는 프로토콜이다. 해당 프로토콜은 기본적으로 Stateless이다. Stateless란 각각의 HTTP 요청이 서로 독립적이며, 이전 또는 다음 요청과 상관관계가 없다는 것을 의미한다. 이는 각각의 HTTP 요청이 서버와 클라이언트 간에 별도의 상태 정보를 유지하지 않고 독립적으로 처리된다는 것을 의미한다.
쉽게 이야기하면 요청이 끝나면, 서버는 너가 누구인지 잊어버린다는 의미이다.
여기가 중요한 포인트이다. 인증의 개념에 보면 서버는 요청이 끝나면, 인증을 잊어버리기 때문에 요청할 때마다 인증정보를 보내줘야 한다.
그럴 때 사용하는 방식 중 하나가 세션(Session)이다.
세션이란
사용자가 아이디와 비밀번호를 입력하고 로그인을 한다고 하면 서버는 세션이라는 식별할 수 있는 별도의 ID를 생성하여 DB(Inmemory, RDB, NoSQL 등 상황에 맞게 사용된다.)에 저장한다. 별도의 생성된 세션을 일반적으로 쿠키에 담아 브라우저로 넘기게 된다. 브라우저는 세션 쿠키를 저장하고 다음 요청을 보낼 때 쿠키를 함께 서버로 전달하여 사용한다.
쿠키에 비밀번호 같은 인증 정보를 저장하는 것이 아닌 사용자의 인증 식별자인 Sesssion id를 저장한다. 서버에는 인증 정보와 더불어 이 ID에 해당하는 사용자 정보를 저장한다.
쿠키를 가진 브라우저는 서버에 요청을 보낼 때 쿠키를 함께 보내게 된다. 그럼 서버는 DB에서 해당 세션이 올바른 세션인지를 검증하고 검증되면 요청에 대한 응답을 보내게 된다. (반대의 경우 예외 호출)
사용자 인증 정보를 서버에서 관리하기 때문에 보안에는 좋지만, 서버 자원을 차지하기 때문에 요청이 많아지면 과부하를 줄 수 있어 성능 저하를 발생하게 된다.
토큰이란?
세션은 위에서 이야기 했듯이 요청이 있을 때마다 DB를 찾고 해야 한다는 문제가 있다. 즉, 유저가 늘어남에 따라 DB 리소스가 많이 발생하게 된다.
이런 이슈를 해결하기 위해 등장한 것이 JWT(Json Web Token)이다. JWT는 토큰 형식이며 어떤 점에서 세션의 문제를 해결할 수 있을지 알아보자.
JWT 구조
JWT는 Header, Payload, Signature로 구성된다.
Header
JWT 토큰은 이상하게 생긴 문자열 개념으로 이해하면 된다. 정확하게 이야기하면 JWT 검증에 필요한 정보를 가진 JSON 객체를 Base64 URL-Safe 인코딩 된 문자열이다. JWT에서 사용할 타입(typ)과 해시 알고리즘(alg)의 종류가 담겨있다.
Payload
JWT의 내용이다. 페이로드에 있는 속성들을 클레임 셋(Claim Set)이라고 부른다. 클레임 셋은 JWT에 대한 내용(토큰 생성자 정보, 생성일시, 만료일시)이나 서버 간 주고받기로 한 데이터로 구성된다.
Signature
점(.)을 구분자로 해서 헤더와 페이로드를 합친 문자열을 서명한 값이다. 서명은 헤더의 alg에 정의된 알고리즘과 개인 키를 이용해 생성하고 Base64 URL-Safe로 인코딩한다. 이는 Header, Payload가 변조되었는지 확인하기 위해 사용되는 중요 정보이며, JWT를 신뢰할 수 있는 토큰인지에 대한 근거가 된다.
세션과의 차이점
JWT 토큰과 세션의 가장 큰 차이점은 인가에 대한 정보를 누가 담고 있냐이다. 세션은 서버의 세션 저장소(DB)에 해당 인증 내용을 담지만, JWT 토큰은 토큰 안에 인증 내용을 담고 있다. 사용자가 요청을 했을 때 토큰만 확인하면 되므로 세션에서 진행한 저장소 인증방법을 하지 않아도된다. 따라서, JWT 토큰을 활용하면 서버에서 토큰을 검증해 주기만 되므로 세션에 비해 과정이 단순해질 수 있다.
세션과 토큰의 장단점
세션 장점
- 인증정보를 모두 DB에 보관하고 있어 해당 정보를 활용한 새로운 기능을 추가할 수 있다.
- 예를 들어 관리자가 특정 유저를 쫒아내고 싶을 때 DB에 세션정보를 날려주면 된다. (강제 로그아웃)
- 여러 디바이스에 로그인 되어 있는 경우 특정 디바이스에 로그아웃을 시킬 수 있다.
- 계정 공유 숫자 제한 등 처리에 용이하다. (DB에 모든 세션정보가 있으니깐)
세션 단점
- 저장소가 필요하며 유저가 늘어난다면 서버부하가 발생하게 된다.
- 이러한 문제 때문에 빠르고 저렴한 Redis를 저장소로 많이 사용한다.
JWT 장점
- signature를 통해 생성되므로 데이터 위변조를 막을 수 있다. (변조 시 검증이 가능함)
- 인증 정보에 대한 별도의 저장소가 필요 없다. (서버 부하를 감소시킨다.)
- JWT는 토큰에 대한 기본 정보과 전달할 정보 및 토큰이 검증되었다는 서명 등 필요한 모든 정보를 자체적으로 지니고 있다.
- 토큰이 한 번 발급되면 유효기간이 만료될 때 까지 사용이 가능하다.
JWT 단점
- 쿠키나 세션과 다르게 JWT 토큰의 길이가 길어 인증 요청이 많아지면 네트워크 부하가 발생할 수 있다.
- 세션에서 구현한 강제 로그아웃 등의 기능을 추가할 수 없다. (해당 토큰이 만료되기 전까지 유효하니깐)
- 토큰을 탈취당하면 대처하기가 어렵다.
JWT 단점 보안을 위한 보안 전략
1. 짧은 만료 기한 설정
토큰의 만료 기간을 짧게 설정하여 탈취되더라도 금방 만료되기 때문에 피해를 최소화할 수 있다. 하지만 사용자가 자주 로그인 해야 하는 불편함이 있다.
2. Sliding Session
예를 들어 특정 작업을 하고 있는 사용자의 토큰이 만료되어 재로그인해야 한다면 큰 이슈이다. 그런것을 보안하기 위해 서비스를 지속적으로 이용하는 사용자에게 자동으로 토큰 만료 기한을 늘려주는 방법이다.
3. Refresh Token
클라이언트가 로그인 요청을 보내면 Access Token 보다 만료시간이 긴 Refresh Token을 함께 전달한다. 클라이언트는 Access Token이 만료되면, Refresh Token을 활용해 Access Token를 재발급한다. 이러한 방식을 Refresh Token을 DB에 저장함으로 검증을 확인하다. 이러한 방식을 이용하면 세션에 확대된 기능의 일부도 추가할 수 있는 장점이 있다.
참고
[김영한 님 강의 모든 개발자를 위한 HTTP 웹 기본 지식]
[노마드 코드 유튜브 - 세션 vs 토큰 vs 쿠키? 기초개념 잡아드림. 10분 순삭!]
'Knowledge > 네트워크' 카테고리의 다른 글
[네크워크] HTTP Status Code(HTTP 상태 코드) (1) | 2023.12.14 |
---|---|
[네크워크] CORS란? (+ Spring Boot에서 설정하기) (0) | 2023.12.12 |
[스친초5기/네트워크] HTTP와 HTTP 메서드 (0) | 2023.11.07 |
[네트워크] 인터넷과 웹의 관계 (1) | 2023.10.23 |
[네트워크] URI와 URL 그리고 URN (0) | 2023.10.10 |