HTTP는 상태를 가지지 않는 무상태(stateless) 프로토콜이다. 서버와 클라이언트간 요청과 응답이 종료되면 연결을 해제(비연결 지향, connectionless)하므로 서버는 클라이언트의 상태를 보존하지 않는다. 이때문에 같은 사용자가 여러번 요청을 하더라도 서버는 매번 새로운 사용자로 인식한다.
하지만 우리가 쇼핑몰을 이용할 때 마음에드는 상품을 장바구니에 넣고 여러 페이지를 돌아다녀도 상품이 유지되고 브라우저를 종료시킨 후 다시 접속했을 때 로그인이 유지되는 것을 볼 수 있다.
HTTP는 상태를 유지하지 않는데 어떻게 정보가 유지될까?
바로 쿠키 덕분이다. 사용자가 웹 사이트에 접속하면 서버는 클라이언트에게 쿠키를 전달하는데 서버는 이 쿠키를 이용하여 클라이언트(브라우저)에 정보를 저장하고 사용자를 식별할 수 있다.
쿠키는 Key와 Value로 구성되며 String 형태로 이루어져 있고 브라우저(사용자)의 정보들이 저장되어있다.
서버는 응답 헤더의 set-Cookie 속성을 이용하여 쿠키의 이름, 값, 경로가 담긴 쿠키를 클라이언트에게 전달한다.
클라이언트에 저장된 쿠키는 매 요청마다 서버에 전달한다.
서버는 쿠키에 담긴 정보를 바탕으로 클라이언트를 식별 하여 로그인을 유지할 수 있다.
브라우저에 데이터를 저장한 이후 서버에서 아무 때나 데이터를 가져올 수 없는데 특정 조건이 만족되어야 다시 가져올 수 있다. 조건들은 http 헤더를 사용해 쿠키 옵션으로 표현한다.
www.google.com과 같은 서버에 접속할 수 있는 이름으로 쿠키 옵션에서 도메인은 서브 도메인 정보(www), 포트(8080), 세부 경로(/user)를 포함하지 않는다.
쿠키 옵션에 Domain이 존재한다면 쿠키 옵션의 Domain과 서버의 Domain이 일치해야만 쿠키를 전송할 수 있다.
요청 URL이 http://www.localhost.com:3000/users/user 일 경우 Domain은 localhost.com 이다.
서버가 라우팅할 때 사용하는 세부 경로를 의미한다. Path를 명시하지 않을 경우 기본적으로 /로 설정되어 있다. Path로 설정된 경로를 포함하는 하위 경로(/user/1)에서 요청을 하더라도 쿠키를 서버에 전송할 수 있다.
요청 URL이 http://www.localhost.com:3000/users/user 일 경우 Path은 /user 이다.
쿠키의 유효 기간을 설정한다. 쿠키가 오래 남아있을 수록 탈취되기 쉬워지기 때문에 보안을 위해 쿠키의 유효 기간을 설정한다. 브라우저가 종료되더라도 이 옵션이 설정되어 있으면 클라이언트는 쿠키를 보관하고 있는다.
MaxAge : 쿠키의 유효 기간을 초 단위로 설정한다.
Expires : 쿠키가 파기되는 날짜를 지정한다. 클라이언트의 시간을 기준으로 하며 지정된 시간이나 날짜를 초과하면 쿠키는 자동으로 파기된다.
프로토콜에 따라 쿠키의 전송 여부를 결정한다. Secure를 true로 설정할 경우 HTTPS를 사용하는 경우에만 쿠키를 전송할 수 있다.
Secure 옵션이 없다면 프로토콜에 상관없이 http, https 모두 쿠키를 전송할 수 있다.
*도메인이 localhost인 경우 HTTPS가 아니어도 쿠키 전송이 가능하다. (개발 단계에서 localhost를 많이 사용하기 때문에 생긴 예외)
자바스크립트로 쿠키에 접근이 가능한지 여부를 설정한다. 기본 설정은 false이며 document.cookie를 이용해 쿠키에 접근할 수 있으므로 쿠키가 탈취될 위험이 있다.
HttpOnly를 true로 설정할 경우 자바스크립트로 쿠키 접근이 불가능하다.
Cross-Origin 요청을 받은 경우 메소드와 SameSite 옵션의 조합을 기준으로 서버의 쿠키 전송 여부를 결정한다.
Lax : Cross-Origin 요청이라면 GET 메소드에 대해서만 쿠키를 전송할 수 있다.
Strict : 가장 엄격한 옵션으로 Cross-Origin이 아닌 same-site 인 경우에만 쿠키를 전송 할 수 있다.
None : Cross-Origin에 대해 가장 관대한 옵션으로 항상 쿠키를 보내줄 수 있다. 하지만 쿠키 옵션 중 Secure 옵션이 필요하다.
*same-site란 요청을 보낸 Origin과 서버의 도메인, 프로토콜, 포트가 같은 경우를 말한다. 하나라도 다를 경우 Cross-Origin으로 구분된다.
서버는 클라이언트에 인증 정보를 담은 쿠키를 전송하고 클라이언트는 전달받은 쿠키를 서버에 요청과 함께 전송하여 Stateless한 인터넷 연결을 Stateful하게 유지할 수 있다.
하지만 기본적으로 쿠키는 오랜 시간 동안 유지될 수 있고 HttpOnly 옵션을 사용하지 않았다면 자바스크립트를 이용해서 쿠키에 접근할 수 있기 때문에 쿠키에 민감한 정보를 담는 것은 위험하다.
이런 인증정보를 이용해 공격자가 유저인척 서버에 요청을 보낸다면 서버는 누가 요청을 보낸 건지 의심하지 않고 인증된 유저의 요청으로 취급하게 된다. 이때 개인정보와 같은 민감한 정보를 공격자가 탈취한다면 2차 피해가 일어날 수 있으므로 보안에 신경써야한다.
로그인을 유지하기 위한 사용자의 정보가 담긴 쿠키는 클라이언트에 저장되어 탈취될 위험이 있다. 하지만 세션은 쿠키와 다르게 데이터(인증 정보)를 클라이언트가 아닌 서버에 저장하고 관리한다.
클라이언트의 (로그인)요청을 받은 서버는 DB에 정보(id, pw)를 저장하거나 유효한지 확인하고 DB는 클라이언트마다 고유한 session_id를 반환한다.
서버는 반환 받은 암호화된 session_id를 저장하고 Set-Cookie를 통해 쿠키에 담아 클라이언트에게 응답한다.
클라이언트는 부여된 session_id를 저장하고 매 요청 시 session_id를 쿠키에 담아 서버에게 전달한다.
서버는 session_id를 확인(인증)하고 유효할 경우 정보를 업데이트를 한 후 클라이언트에게 응답을 보낸다.
세션도 결국 쿠키에 유저 정보를 담지만 인증 권한은 서버가 가지고 session_id를 통해 사용자 식별 및 인증 상태를 유지한다.
쿠키 : 쿠키와 세션의 가장 큰 차이점으로 사용자의 정보가 클라이언트(로컬)에 저장된다.
세션 : 마찬가지로 쿠키에 사용자 정보를 저장하지만 session_id를 이용하여 서버에서 관리 및 저장된다.
쿠키 : 서버의 자원을 사용하지 않으므로 처리 속도가 세션보다 빠르다.
세션 : 정보가 서버에 저장되어 있기 때문에 처리가 요구되므로 쿠키에 비해 비교적 느리다. 또한 사용자의 수 만큼 서버의 메모리를 차지한다.
쿠키 : 클라이언트에 저장되기 때문에 변질되거나 요청 시 탈취당할 위험이 있다.
세션 : session_id를 서버에서 저장하고 식별하기 때문에 쿠키보다 비교적 안전하다.
쿠키 : 브라우저가 종료되더라도 만료기간이 남아있다면 유지된다.
세션 : 브라우저가 종료되면 만료기간에 상관없이 삭제된다.