안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

웹, 앱 (Web, Application)

[Web] 쿠키와 세션 (Cookie and Session)

피그브라더 2020. 1. 9. 21:56

세션과 쿠키는 둘 다 사용자가 특정 서버의 웹사이트에 방문했던 정보를 기억하고 해당 서버가 이를 재사용하기 위한 수단이다. 각각의 특성을 한 번 간단하게 알아보고 넘어가자.

 

1. HTTP 프로토콜의 특성

전 세계의 사람들은 인터넷이 연결된 환경 하에서 웹이라는 통로로 서로 통신한다. 이때 서로 다른 특성을 가진 기기들이 통신을 할 수 있도록 미리 합의하여 정해놓은 통신 규약을 프로토콜이라 부르며, HTTP는 웹에서 사용하는 프로토콜이다. 쿠키와 세션을 알아보기에 앞서, HTTP 프로토콜의 다음 두 가지의 특성을 짚고 넘어가자.

 

특성 설명
Connectionless  클라이언트가 요청을 보내고 서버가 응답하면 그 즉시 해당 연결은 종료된다.
Stateless 연결이 끊어지면 그 전의 상태 정보는 유지되지 않고 소멸된다(따로 기억되지 않는다).

 

쿠키와 세션을 설명하는 데 있어 이것이 왜 중요할까? 버거킹을 예로 들어 설명해 보겠다.

 

버거킹에 가서 햄버거를 주문하는 한 고객을 C라고 하고, 햄버거를 만들어서 고객에게 주는 한 직원을 S라고 하자. 그러면 C와 S는 정확히 'C가 햄버거를 주문하고 S가 햄버거를 줄 때까지'만 소통한다(Connectionless). 또한 설명의 편의를 위해 S의 기억력이 아주 나빠서 방금 전 온 손님도 기억하지 못한다고 해보자(서버는 클라이언트의 방문 정보를 특별히 기록하지 않는다). 그러면 S는 방금 전에 주문했던 C가 다시 와서 주문해도 그를 알아보지 못한다(Stateless).

 

이때, 버거킹이 전날 방문한 고객에게는 10% 할인을 해주는 이벤트를 진행한다고 해보자. 그러려면 S는 C가 다시 방문했을 때 C를 알아볼 방법이 필요하다. 그러면 다음과 같은 방법을 생각해볼 수 있다.

 

① 처음 방문 시 S가 C의 방문 정보를 사물함에 저장한 뒤 그 열쇠를 C에게 발급해주고, C는 재방문 시 해당 열쇠를 S에게 제공한다.

② 처음 방문 시 S가 C의 방문 정보를 담은 카드를 만든 뒤 그 카드를 C에게 주고, C는 재방문 시 해당 카드를 S에게 건네준다.

 

이것이 (내가 생각하기에) 쿠키와 세션을 가장 쉽게 이해하는 방법이다. ①의 경우 S는 C가 재방문 시 제공한 열쇠를 가지고 사물함을 찾아 열어봄으로써 C의 방문 정보를 확인할 수 있다. ②의 경우에는 C가 건네주는 카드를 보고 C의 방문 정보를 확인할 수 있다. 여기서 핵심은 다음과 같다. C가 전날 방문한 것과 관련한 정보를 ①은 S 쪽에 저장해둔 것이고, ②는 C 쪽에 저장해뒀다는 것이다. 이후부터 설명할 세션과 쿠키는 각각 ①과 ②에 대응된다고 생각하면 된다. 서버 쪽에 저장하는 사용자의 방문 정보가 세션이고, 클라이언트 쪽에 저장하는 사용자의 방문 정보가 쿠키이다.

 

2. 쿠키 (Cookie)

2-1. 의미

쿠키란, 클라이언트가 브라우저를 통해 특정 서버의 웹사이트에 방문했던 상태 정보를 기억하기 위해서, 클라이언트의 하드디스크 혹은 브라우저의 메모리에 저장하는 작은 정보 조각들을 의미한다. 최대 4KB의 데이터를 저장할 수 있다.

 

2-2. 종류

종류 설명
세션 쿠키 (메모리 쿠키, 브라우저 쿠키) 클라이언트가 사용하는 브라우저의 메모리에 저장되는 쿠키로, 한 세션 동안 유효하다. (세션의 설명은 아래 세션 관련 내용 참조) 즉, 유효 기간이 명시되지 않은 쿠키를 의미한다.
영구 쿠키
클라이언트의 하드디스크에 저장되는 쿠키로서, 명시된 유효 기간 동안 유효하고, 유효 기간이 지나면 삭제된다.

 

2-3. 장단점

장점 단점
정보를 서버가 아닌 클라이언트에 저장하기 때문에 서버의 부하를 줄일 수 있다. 서버보다 보안이 취약한 클라이언트에 정보를 저장하기 때문에 보안 위협에 취약할 수 있다.

 

2-4. 동작 방식

클라이언트가 웹사이트에게 요청을 전송한다.
서버에서 그 요청의 정보를 담은 쿠키를 생성한다(저장하지는 않는다).
해당 쿠키를 응답의 set-cookie 헤더에 담아 클라이언트에게 전송한다.
클라이언트는 전송받은 쿠키를 하드디스크 혹은 브라우저의 메모리에 저장한다.
이후 클라이언트가 동일한 웹사이트에게 다시 요청을 하면, 저장하고 있던 쿠키를 요청의 cookie 헤더에 담아 서버에게 전송한다.
서버는 전송받은 쿠키를 통해 이전 상태 정보를 확인하고, 이에 맞게 클라이언트에게 적절한 방식으로 응답한다. 만약 업데이트해야 할 상태 정보가 있다면 변경된 쿠키를 응답의 set-cookie 헤더에 담아 클라이언트에게 전송한다.

 

2-5. 사용 예시

  • "오늘 더 이상 이 창을 보지 않음" (더 이상 이 창을 보지 않을 거라는 사실을 JavaScript로 쿠키에 세팅하고, 이를 서버에게 매번 전송하면 서버는 이 창을 띄우지 않음)
  • 쇼핑몰 장바구니 (내가 찜해 놓은 상품들의 목록을 JavaScript로 쿠키에 세팅하고, 이를 서버에게 전송하면 서버는 필요할 때 그 목록을 보여줄 수 있음)

 

2-6. 쿠키 보안 옵션 : Secure, HttpOnly

  • 쿠키의 안전한 전송을 위해서 서버가 응답의 헤더(set-cookie 헤더)에서 설정해주는 옵션들을 말한다. 물론 브라우저에서 JavaScript를 이용하여 쿠키를 세팅할 때도 이러한 옵션들을 설정해줄 수 있다.
  • Secure 옵션
    • HTTPS 프로토콜을 사용하는 경우에만 브라우저가 서버에게 전송하도록 하고 싶은 쿠키에게 주는 옵션이다.
    • 즉, HTTP 프로토콜을 사용하는 경우 Secure 옵션이 설정된 쿠키는 서버에 전송되는 요청의 헤더에 포함되지 않는다.
    • Secure 옵션을 설정하고 싶은 쿠키는 'KEY=VALUE; Secure' 형식으로 세팅한다.
    • 접속한 사용자를 식별하기 위해 사용하는 session_id 등의 쿠키는 Secure 옵션을 설정하는 것이 좋다. session_id만 탈취한다면 다른 사람이 나인 것처럼 흉내 내는 것이 가능하기 때문이다. HTTPS 프로토콜은 데이터를 전송할 때 기본적으로 암호화를 하기 때문에 HTTP 프로토콜보다 안전하다.
  • HttpOnly 옵션
    • 브라우저에서 JavaScript로 접근할 수 없도록 하고 싶은 쿠키에 주는 옵션이다.
    • 즉, HttpOnly 옵션이 설정된 쿠키는 서버에 전송되는 것만 가능하다.
    • 이를 통해 XSS(Cross Site Scripting) 방식으로 특정 쿠키가 탈취되는 일을 예방할 수 있다.
    • Secure 옵션과 마찬가지로, session_id 등의 중요한 쿠키에는 이 옵션을 설정해주는 것이 좋다.
  • SameSite 옵션
    • 다른 도메인에서의 쿠키 전송에 관한 보안을 설정하는 옵션이다.
    • None : 어떠한 도메인에서든지 쿠키 전송이 가능하다.
    • Strict : 오직 동일한 도메인에서만 쿠키 전송이 가능하다. (CSRF 방지)
    • Lax : Strict 설정에 일부 예외(HTTP GET 메소드, a 태그의 href, link 태그의 href 등)를 둔 것이다. (※ 크롬 80부터는 이것이 SameSite 옵션의 기본값이다.)

 

※ 다른 오리진(= 프로토콜 + 도메인 + 포트) or 다른 도메인에 대한 이슈

1. 브라우저의 CORS 정책은 다른 오리진에 대한 요청을 막음 :
브라우저는 다른 오리진에 요청을 보낼 때 요청의 Origin 헤더에 자신의 오리진을 실어 보낸다. 그리고 서버는 응답 시에 응답의 Access-Control-Allow-Origin 헤더에 허용되는 오리진들의 목록을 실어 보낸다. 그러면 브라우저는 이 두 헤더의 값을 비교하여 허용되는 오리진에 대한 요청일 경우에만 해당 응답을 채택한다. 따라서 백 엔드 서버에서 Access-Control-Allow-Origin 헤더를 설정해주지 않으면 CORS 요청은 막힐 것이다.

2. 다른 오리진에 대한 요청 시에는 쿠키를 전송 혹은 수신할 수 없음 :
브라우저가 다른 오리진에 요청을 보낼 때 별도의 설정을 해주지 않으면 쿠키를 보낼 수도 없고, 받을 수도 없다. 해당 설정은 요청을 보내는 방식에 따라 다르다. 만약 XMLHttpRequest, jQuery의 ajax, 또는 axios를 사용한다면 withCredentials 옵션을 true로 설정해줘야 하고, fetch API를 사용한다면 credentials 옵션을 include로 설정해줘야 한다. 그리고 서버에서도 응답 시에 응답의 Access-Control-Allow-Credentials 헤더 값을 true로 설정해줘야 하고, Access-Control-Allow-Origin 헤더 값에는 *를 사용하지 않아야 한다. 그래야 브라우저가 해당 응답을 채택할 수 있다. (참고)

3. JavaScript로 읽을 수 있는 쿠키의 범위 (HttpOnly 옵션이 false임을 가정) :
JavaScript에서 쿠키는 document.cookie를 통해 상위 도메인의 쿠키까지 읽을 수 있다. 예를 들어, sub.example.org에서는 sub.example.org의 쿠키뿐 아니라 example.org의 쿠키까지 읽을 수 있다. 따라서 상위 도메인이 같은 다른 하위 도메인들의 경우 서로의 쿠키를 읽을 수 없다. 예를 들어, sub1.example.org에서는 sub2.example.org의 쿠키를 읽을 수 없다. 이것이 가능하려면 해당 쿠키를 설정할 때 domain=example.org 옵션을 설정해줘야 한다. (참고)

4. 하위 도메인(sub.example.org)의 백 엔드 서버에서 응답 시에 쿠키를 설정해주는 방법 :
서버는 응답 시 쿠키의 domain 옵션을 명시적으로 설정해줄 수 있다(단, 자기 자신 혹은 자기 자신의 상위 도메인으로만 설정해줄 수 있으며, 그렇지 않으면 브라우저가 해당 쿠키를 무시). 설정해주지 않으면 기본값은 자기 자신이다. 예를 들어, sub.example.org의 백 엔드 서버가 응답 시 쿠키의 domain 옵션을 설정해주지 않으면 domain 옵션의 기본값은 sub.example.org로 설정된다. 하지만 domain 옵션의 값을 example.org로 명시적으로 설정해줄 수도 있고, 그러면 example.org에 해당하는 웹사이트에서도 해당 쿠키를 참조할 수 있게 된다. (참고)

5. 쿠키의 SameSite 옵션은 기본값이 Lax :
GET 등의 안전한 요청이 아닌 이상 동일한 사이트일 때만 해당 쿠키를 전송하도록 하는 옵션이다. 여기서 말하는 동일한 사이트란 1차 도메인과 2차 도메인의 조합을 의미한다. 즉, a.example.org와 b.example.org는 동일한 사이트이다. (참고)

 

3. 세션 (Session)

3-1. 의미

세션이란, 사용자가 브라우저를 통해 웹사이트에 접속한 시점부터 브라우저를 종료함으로써 연결을 끝내는 시점까지의 기간, 혹은 그 기간 동안 같은 사용자로부터의 일련의 요구를 하나의 상태로 식별하기 위한 정보를 의미한다.

 

3-2. 장단점

장점 단점
클라이언트보다 보안이 강한 서버에 저장이 되기 때문에 보안 위협에 덜 취약하다. 사용자가 많아지면 서버의 부하가 심해질 수도 있다.

 

3-3. 동작 방식

클라이언트가 웹사이트에 처음 접속한다. 이때는 요청의 cookie 헤더에 세션 ID가 없다.
서버는 요청에 세션 ID가 없음을 확인하고 (세션 생성이 필요한 경우라면) 새로운 세션을 생성한 뒤 해당 세션 ID를 발급한다.
해당 세션 ID를 응답의 set-cookie 헤더에 담아 클라이언트에게 전송한다.
클라이언트는 전송받은 세션 ID를 쿠키로 저장한다.
이후 클라이언트가 동일한 웹사이트에게 다시 요청을 하면 요청의 cookie 헤더에 세션 ID를 담아 서버에게 전송함으로써 하나의 세션이 유지되고 서버가 클라이언트를 식별할 수 있게 한다.

 

3-4. 사용 예시 (로그인 상태 유지)

  • 세션을 사용하지 않으면 사용자는 매 페이지마다 아이디와 패스워드를 서버에 전송함으로써 인증을 완료해야 한다.
  • 하지만 이것은 매우 귀찮은 일이고, 무엇보다 매번 개인정보를 요청으로 보내는 것은 보안에 상당히 취약하다.
  • 그렇기 때문에 쿠키와 세션을 사용하여 로그인 상태를 유지하도록 한다. 방법은 다음과 같다.
    • 사용자가 로그인을 한다.
    • 해당 사용자의 세션이 생성되어 있지 않으면 우선 세션을 생성하여 세션 ID를 발급한다.
    • 세션에 사용자의 고유한 ID를 저장한다.
    • 세션 ID를 응답의 set-cookie 헤더에 담아 클라이언트에게 전송한다.
    • 이제 그 사용자는 해당 웹사이트의 어느 곳을 방문하든 세션 ID를 요청의 cookie 헤더에 담아 전송한다.
    • 이로 인해 서버는 접속한 사용자가 누구인지 쉽게 식별이 가능하며, 로그인 상태를 유지시켜줄 수 있다.
    • 만약 해당 사용자가 로그아웃을 하면, 해당 세션이 서버에서 삭제가 된다.