Cookie

GI JUNG·2023년 3월 9일
2

nodejs

목록 보기
6/6
post-thumbnail
post-custom-banner

사용자는 어떤 서비스를 이용하기 위해서는 자신이 누구인지 신뢰할 수 있는 지 에 대해서 인증을 거치고 권한을 얻을 수 있다. 인증을 거치는 절차에 있어서 Cookie, Session, Token, OAuth가 대표적으로 사용되며 로그인(사용자를 인증하고 권한을 제어하는 행위) 할 때를 예시를 들 수가 있다.

🍀 Cookie

🤔 쿠키는 어떻게 사용되며 왜 사용할까???

위에서도 언급했듯이 인증을 하기 위해서 쿠키를 사용하며 쿠키를 통해 사용자를 인증할 수 있다. 이 때 쿠키는 데이터를 저장하는 조각이라 생각할 수 있다.
한 마디로, 쿠키에 담긴 정보를 토대로 인증을 진행한다.
쿠키를 사용하는 또 다른 이유는 HTTP(Hyper Text Transfer Protocol)에 있다.
쿠키가 나온 이유를 설명하기 위해 http를 간략하게 소개하자면 http는 아래와 같이 크게 두 가지 특징 stateless, connectionless 의 특징을 가진다.

http는 웹에서 문서를 주고 받기 위해 지정된 통신규약 이다.

http 특징
1. stateless(비상태성): 상태를 저장하지 않음
2. connectionless(비연결성): 클라이언트와 서버 사이의 연결을 유지하지 않음

웹 사이트에서 정보를 주고 받기 위해서 HTTP를 이용하지만 HTTP의 stateless(비상태성) 으로 인해 HTTP는 상태를 저장하지 않는다. 이 말은, 클라이언트와 서버가 통신 함에 있어서 정보를 저장할 수단이 없다는 것이다. 따라서, 정보를 저장하여 인증을 하기 위해 쿠키가 나온 이유 중에 하나다.

쿠키를 이용함으로써 장바구니에 저장된 아이템, 테마, 언어 등 다양한 정보를 이용하여 클라이언트에 따라 각기 다른 서비스를 제공할 수 있다. 또한 사용자의 행동을 분석하여 tracking할 때도 쓰인다.

쿠키 확인해보기 👇
아래 이미지는 내가 네이버에 로그인을 했을 때 네이버에서 내 브라우저에 보내준 쿠키들이다.
이미지에서 빨간 박스는 쿠키를 어떻게 설정할지에 대한 option 이다.
cookie-in-developer-tools

쿠키는 서버가 클라이언트에게 설정을 하면 이후 클라이언트 → 서버, 서버 → 클라이언트 간의 소통에서 쿠키는 자동으로 http header에 담겨서 전송된다.

  1. 쿠키는 http header에 담긴다
  2. 클라이언트에서 서버, 서버에서 클라이언트 사이의 상호작용에서 쿠키는 자동으로 담긴다.

cookie-created-by-server

위에서 대충 쿠키가 어떤 놈인지 알아봤으니 쿠키에 대해서 정리해보면 아래와 같다.

쿠키의 특징

  1. 쿠키는 정보를 저장할 수 있다.
  2. 쿠키는 클라이언트에 저장된다.
  3. 클라이언트에 최대 300개 쿠키를 저장 가능.
  4. 하나의 도메인 당 20개의 쿠키를 가질 수 있다.
  5. 하나의 쿠키는 4KB(=4096byte)까지 저장 가능하여 큰 데이터는 적합하지 않다.

쿠키 동작 순서

  1. 사용자가 웹사이트에 접근한다.
  2. 클라이언트가 서버로 페이지를 요청한다.
  3. 서버는 필요한 정보를 담아 쿠키를 생성하여 클라이언트에게 HTTP header에 담아 응답한다.
  4. 서버로부터 받은 쿠키는 클라이언트가 Storage에 저장한다.
  5. 이후 동일 사이트 재방문시 클라이언트의 PC에 해당 쿠키가 있는 경우, 요청 페이지와 함께 쿠키를 전송한다.

cookie-flow

쿠키 옵션은 여러가지만 있지만 자주 쓰이는 것들인 Domain, Path, MaxAge, Expire, Secure, HttpOnly, SameSite 를 위주로 다룬다.

1. Domain

domain option은 쿠키의 도메인 옵션과 서버의 도메인이 같아야만 쿠키를 전송할 수 있다.

도메인에 대해서 간략히 설명하자면, 브라우저에서 [http://www.localhost:4000/user/info](http://www.localhost:4000/user/info) 로 요청을 보낸다고 하면, 여기서 도메인은 localhost 가 된다. 다른 예를 들자면 [https://www.naver.com](https://www.naver.com) 이 있다면 도메인은 naver.com 이 된다.
즉, 쿠키 옵션에서 도메인에 대한 정보는 포트 및 서브 도메인 정보를 제외하고 딱 도메인 만을 의미한다.

이렇게 쿠키에서 domain option을 설정하게 되면 kakao로 보내야 할 쿠키를 naver로 잘못 보내는 일을 막을 수 있다.

2. Path

path option은 서버에서 라우팅할 때 사용되는 경로에 쿠키를 보낼 수 있는지에 대한 여부이다.

path는 [http://www.localhost:4000/user](http://www.localhost:4000/user/info) 와 같은 url에서 /user 가 path이다.
또한 path에 설정된 경로의 하위 경로에게도 쿠키를 보낼 수 있다.
예시를 들자면 요청하는 url이 [http://www.localhost:4000/user/info](http://www.localhost:4000/user/info) 이고 path=”/user”라면 /user/info는 /user의 하위 경로이므로 쿠키를 보낼 수 있다는 것이다.

path의 default 값은 / 이다.

3. MaxAge

쿠키를 통해서 서버에게 인증을 한다고 했다. 하지만 만약에 쿠키가 탈취된다면??? 쿠키를 가지고 다른 사람이 인증하면 큰일날 것이다. 이러한 경우를 대비해 쿠키가 유효한 기간을 정해 줄 수 있는데 이에 대한 옵션이 MaxAge이다.

MaxAge의 값으로는 ms단위가 아닌 초(s)단위를 가지며 정해 준 시간이 지나면 쿠키는 파괴된다.

4. Expires

Expires option은 MaxAge와 같은 옵션이지만 값에 날짜를 지정해 준다. 즉, 만료날짜를 지정해준다.
여기서 MaxAge 또는 Expires를 지정하냐 지정하지 않냐에 따라서 Session Cookie(임시쿠키, 세션쿠키)와 Persistent cookie)로 나뉜다.

  • session cookie: cookie option에 MaxAge 또는 Expires를 지정해주지 않고 생성된 쿠키로서 브라우저가 실행 중일 때만 유효하고 브라우저를 끄면 사라지는 쿠키이다.
  • persistent cookie: session cookie와 다르게 MaxAge 또는 Expires option을 지정하여 생성된 쿠키로서 주어진 시간 동안만 살아있고 주어진 시간이 지나면 파기된다.

5. Secure

secure option은 http와 https에 따라 쿠키를 전송할 수 있는지에 대한 여부를 결정짓는 옵션이다.
하지만, localhost에서 개발을 많이 하므로 예외적으로 localhost에서는 Secure: true여도 http 요청을 할 수 있다.

  • secure: true ⇒ https통신에만 쿠키를 전송할 수 있으며, http통신에는 전송할 수 없다.
  • secure: false ⇒ false는 default 값으로 http와 https 통신에 모두 쿠키를 전송할 수 있다.

6. HttpOnly

스크립트(javascript)로 브라우저의 쿠키에 접근할 수 있는지에 대한 여부이다. javascript로 document.cookie 를 이용하여 쿠키를 얻을 수 있는데 이를 허용할지 말지인 것이다.

  • HttpOnly: true스크립트로 쿠키에 접근을 허용하지 않는다.
  • HttpOnly: false스크립트로 쿠키에 접근을 허용한다.

7. SameSite

Cross-Origin 요청과 Same-Stie인 경우에 대해서 쿠키를 전송할 수 있는지에 대한 여부이다.
Cross-Origin이 궁금하다면 CORS와 SOP를 공부해보면 알 수 있다.

  • SameSite: LaxCross-Origin요청일 시 GET메서드에 대해서만 쿠키 전송 가능하다. same-site라면 메서드에 상관없이 쿠키 전송이 가능하다.
  • SameSite: Strict ⇒ 모든 Cross-Origin요청은 쿠키전송이 불가능하다. 즉, same-site요청일 시에만 쿠키전송 가능.
  • SameSite: None ⇒ 모든 Cross-Origin요청에 대해 메서드들과 상관없이 쿠키전송이 가능하지만, Secure: true 옵션이 필요하다

☁️ 쿠키 생성해 보기

간단한 쿠키 생성

// server.js
const http = require("http");
const PORT = 4000;

const server = http
  .createServer((req, res) => {
    res.writeHead(200, {
      "Set-Cookie": ["name=jjung", "address=seoul"],
    });
    res.end();
  })
  .listen(PORT, () => console.log(`server is listening at PORT: ${PORT}`));

simple-created-cookie

express와 cookie option 지정

res.cookie 는 express에서 제공하는 메서드이다.

// server.js

const express = require("express");
const PORT = 4000;

// session cookie
const nameCookieOptions = {
  domain: "localhost",
  path: "/",
  httpOnly: true, // script로 쿠키 접근 불가
  secure: true, // sameSite가 none이므로 secure option은 필수적으로 설정 필요
  sameSite: "none",
};

// persistent cookie
const addressCookieOptions = {
  domain: "localhost",
  path: "/",
  httpOnly: true,
  secure: true,
  sameSite: "none",
  expires: new Date(Date.now() + 1000 * 60 * 5),
};

const app = express();

app.get("/", (_, res) => {
  res.cookie("name", "jjung", nameCookieOptions);
  res.cookie("address", "seoul", addressCookieOptions);
  res.status(200).send("<h1>I got cookies!!</h1>");
});

app.listen(PORT, () => console.log(`server is listening at PORT: ${PORT}`));

cookie-with-options

MaxAge 또는 Expires의 지정 여부에 따라 nameCookie는 session cookie 이며 addressCookie는 persistent cookie 가 됨을 알 수 있고 설정한 cookie option에 따라 잘 들어간 것을 확인할 수 있다.

🔥 마치며

쿠키를 이용하여 원하는 정보를 client에 담을 수 있음을 알았다. 하지만, 크롬 개발자 도구에서 cookie의 name과 value가 그냥 보인다…. 이는 보안의 취약점이 아닐 수가 없다… 만약에 비밀번호와 같은 것이 그대로 cookie에 담겨 외부인에게 노출된다면…. 흠… 비밀번호를 암호화하던 해야 할 것 같다. 아니면, server에서 비밀번호를 저장해 놓고 client에는 비밀번호를 제외한 쿠키를 놓든 하는 것도 방법일 듯 하다. 그리고 쿠키는 XXS, CSRF 공격에 취약하다는데 추가적으로 공부하면 좋을 듯 하다.

📚 참고

http reference
MaxAge VS Expires
CORS and CSRF
CORS and SOP
참고하면 좋은 사이트

profile
step by step
post-custom-banner

0개의 댓글