쿠키와 토큰
1. HTTP가 사용자를 식별하는 방법
- Http Header: 사용자의 이메일 주소, 브라우저 정보, 사용자가 현재 링크를 타고 온 근원 페이지 등의 정보를 헤더에 담는다.
- 클라이언트 IP address: 웹 초기에 쓰이던 방법이다. 단점으로는 여러 명의 사용자가 같은 컴퓨터를 사용하는 경우 각각의 사용자를 구별할 수 없고, 동적 IP 주소 할당으로 인해 한 사용자가 매번 다른 IP 주소를 사용하게 되는 환경에서는 쓸모가 없다. 또한 프록시가 있는 경우에도 클라이언트의 IP 대신 프록시의 IP를 보아서 식별에 실패한다.
- 사용자 로그인 인증:
Authorization Header
를 사용해 웹사이트에 사용자 정보를 전달한다. - URL에 식별자 포함: 이런 방식을 fat URL이라고 하는데, 단점으로는 URL이 못생겨지고, 특정 사용자의 정보를 포함하고 있기 때문에 공유할 수 없는 URL이 되고, 기존 URL이 달라지기 때문에 캐시를 사용할 수 없고, 사용자가 fat URL에서 이탈하기 쉽고, 세션 간 지속성이 없어진다는 점이 있다.
- 쿠키: 쿠키는 크게 세션 쿠키와 지속 쿠키로 나눌 수 있다.
- 세션 쿠키는 사용자가 사이트를 탐색할 때, 관련된 설정과 선호 사항들을 저장하는 임시 쿠키이다. 세션 쿠키는 사용자가 브라우저를 닫으면 삭제된다.
- 지속 쿠키는 삭제되지 않고 더 길게 유지될 수 있다. 지속 쿠키는 디스크에 저장되어 브라우저를 닫거나 컴퓨터를 재시작하더라도 남아있다.
- 둘의 차이는 파기되는 시점 뿐이다. 또한 특별히 쿠키가 캐싱되지 않도록 주의해야 한다.
2. 세션과 쿠키
둘 다 정보를 저장하기 위해 쓰인다. 쿠키는 클라이언트측에만 저장되고, 세션은 클라이언트와 서버 둘 다에 저장될 수 있다.
세션은 서버에 임시 폴더와 파일을 만든다. 세션으로 저장된 데이터는 사용자가 다른 페이지로 옮겨다녀도 유지된다. 세션 기록은 사용자가 브라우저를 닫거나 사이트를 떠났을 때 끝나고, 서버는 특정 시간이 지난 후 세션을 파기한다. 보통 30분 주기로 이루어진다.
쿠키는 클라이언트 컴퓨터에 저장되는 텍스트 파일이다. 서버측 스크립트는 이름, 나이 등과 같은 쿠키 정보들을 브라우저에 전달하고, 브라우저는 이 정보들을 바탕으로 사용자에게 맞춤 제품 추천, 연관 광고 띄우기 등을 수행한다.
세션과 쿠키를 둘 다 쓸 수 없다면 토큰을 쓰거나 데이터베이스를 써야 한다. 데이터베이스도 쓸 수 없다면 인메모리 캐시를 쓸 수 있을 것이다. 웬만하면 쿠키를 쓸 수 있다면 쿠키를 쓰는 것이 좋다.
2-1. 세션을 이용한 로그인 과정
- 사용자가 아이디와 비밀번호를 입력해 서버에게 로그인 요청을 보낸다.
- 서버는 요청받은 정보를 검사하고, 그 값이 정확한지 체크한 후, 문제가 없으면 세션을 만들어 로그인중인 리스트에 해당 유저를 추가하고 클라이언트에게 HTTP 응답코드 200과 함께 요청받은 문서를 보낸다.
- 로그인중인 유저를 확인할 때에는 매 요청마다 서버가 세션 저장소에서 세션을 읽은 후, 클라이언트로 응답한다.
3. JWT JSON Web Token
JWT는 토큰 기반 인증 시스템의 구현체이다.
세션과 같이 서버 측에서 유저들의 정보를 기억하고 있어야 하는 서버 기반 인증은 몇 가지 문제점이 있다.
- 유저가 로그인을 위해 서버로 인증 요청을 보낼 때, 서버는 이 기록을 세션으로 메모리에 저장해야 한다.
- 로그인중인 유저의 수가 늘어날 경우 서버에 과부하가 걸릴 수 있다. 서버 대신 DB에 세션을 저장할 수도 있지만, 이 역시 부하를 그대로 DB에 전가하는 것 뿐이다.
- 세션 시스템을 사용하면서 서버를 확장하는 것은 매우 까다롭다.
토큰 기반 인증 시스템은 Stateless하다. 유저의 인증 정보를 서버나 세션에 담아두지 않는다. 따라서 서버 확장이 용이하고, 클라이언트가 서버에 요청을 보낼 때 더이상 쿠키를 전달하지 않아도 되고, 쿠키가 여러 도메인에서 작동하도록 추가로 설정할 필요가 없다.
JWT는 웹 표준 RFC 7519에 등록되어있다.
3-1. 토큰을 이용한 로그인 과정
- 유저가 아이디와 비밀번호로 로그인을 한다.
- 서버측에서 해당 계정 정보를 검증하고, 계정 정보가 정확하다면 서버측에서 유저에게 토큰을 발급해준다.
- 클라이언트측에서 전달받은 토큰을 저장해두고, 서버에 요청을 할 때마다 해당 토큰을 HTTP Header에 담아 함께 서버에 전달한다.
- 서버는 토큰을 검증하고, 요청에 응답한다.
4. 로컬 스토리지와 세션 스토리지, 쿠키
로컬 스토리지와 세션 스토리지는 HTML5에서 추가된 저장소로, key-value 스토리지의 형태이다.
로컬 스토리지의 데이터는 사용자가 지우지 않는 이상 영구적으로 브라우저에 남아있지만, 세션 스토리지의 데이터는 윈도우나 브라우저 탭을 닫을 때 제거된다. 자동 로그인 등 지속적으로 필요한 데이터는 로컬 스토리지에, 일회성 로그인 정보같은 것들은 세션 스토리지에 저장하면 된다
쿠키는 만료 기한이 있는 key-value 스토리지로, 로컬 스토리지와 세션 스토리지가 나오기 이전부터 서버와 클라이언트 간의 지속적인 데이터 교환을 위해 만들어졌다.
쿠키보다 로컬 스토리지가 더 좋은 성능을 보인다. 쿠키는 매 HTTP 요청마다 Request Header에 포함되어 서버에 전달되는데, 매번 필요하지 않은 데이터가 전달되는 것은 낭비이다. 로컬 스토리지는 쿠키와 다르게 용량이 크며, HTTP 요청 때 전달되지 않고, 보안을 강화할 수 있다.
쿠키는 보통 setCookie()
, getCookie()
함수 안에서 document.cookie
를 사용하고, 스토리지는 localStorage.setItem()
, getItem()
, remove()
, clear()
등의 함수를 사용한다.