WEB - 쿠키로 토큰 관리하기

Yuni·2023년 6월 28일
1

WEB

목록 보기
9/12
post-thumbnail

서론

이전 포스트에서 세션과 토큰 인증방식에 대해서 알아보며 마지막에 쿠키에 대한 언급을 드렸는데요. 쿠키의 자동전송과 보안성, 지속성등의 대한 이유로 최근에는 토큰을 쿠키에 담는 방식이 많이 사용되고 있습니다. 세션,로컬 스토리지에 저장하지 않고 토큰을 쿠키에 담는 방식이 쓰이는 이유에 대해서 자세히 알아보겠습니다.

쿠키란 무엇인가

쿠키는 크롬이나 사파리 등 웹 사이트가 웹 브라우저에 저장하는 작은 데이터 조각입니다. 이 데이터 조각은 클라이언트와 서버 간의 상호작용을 추적하고, 클라이언트의 상태 정보를 저장하고 전달하는 데 사용됩니다. 일반적으로 쿠키는 이름, 값, 만료 날짜/시간, 도메인 및 경로와 같은 사용자에게 맡겨도 되는 정보만 저장합니다. 더 자세한 설명은 🔗여기에서 확인해 보세요 🙂

왜 쿠키일까?

  • 상태 유지: 쿠키를 사용하여 토큰을 저장하면, 클라이언트는 매 요청 시 해당 쿠키를 서버에 함께 전송하여 인증 상태를 유지할 수 있습니다. 물론 토큰 인증 방식에도 인증 상태를 유지할 수 있지만, 토큰을 매번 "Authorization" 헤더에 토큰을 담아서 전송해야 합니다.쿠키를 사용하여 토큰을 관리하는 방식도 마찬가지로, 클라이언트는 매 요청 시 쿠키를 함께 전송하여 서버에 인증 상태를 유지할 수 있습니다. 다만, 쿠키는 HTTP 요청 헤더에 자동으로 포함되기 때문에 개발자가 별도로 헤더에 토큰을 추가하지 않아도 됩니다.
  • 보안: 쿠키는 브라우저가 자동으로 관리하기 때문에, 클라이언트에서 직접 토큰을 관리하는 것보다 보안 측면에서 유리합니다. 클라이언트 측에서 토큰을 관리하면, 토큰이 브라우저 내부에서 노출될 수 있는 위험이 있고, 조작당하기 쉽습니다. 하지만 쿠키에 저장된 토큰은 브라우저가 관리하므로, 외부에서 접근하기 어려워 토큰 + 세션/로컬스토리지 방식을 사용했을 때 보다 보안성이 좋습니다.

  • CSRF 방지: 쿠키를 사용하여 토큰을 전달하는 경우, 토큰은 쿠키에 저장되어 있으며, 브라우저가 자동으로 이를 요청과 함께 전송합니다. 이는 Cross-Site Request Forgery (CSRF)와 같은 공격을 방지하는 데 도움이 됩니다. CSRF 공격에서는 악의적인 웹 사이트가 사용자의 인증 정보를 탈취하여 악의적인 요청을 전송할 수 있습니다. 하지만 쿠키를 사용하여 토큰을 전달하면, 악의적인 웹 사이트는 클라이언트의 쿠키에 접근할 수 없어 CSRF 공격을 어렵게 만듭니다.

예시코드

아래는 Express.js 미들웨어를 사용하여 토큰을 쿠키에 담는 간단한 예시코드입니다.

const express = require('express');
const cookieParser = require('cookie-parser');

const app = express();
app.use(cookieParser());

app.get('/login', (req, res) => {
  // 토큰 생성 로직 생략
  const token = 'sample_token';

  // 쿠키에 토큰을 담음
  res.cookie('token', token, {
      path: '/',
      domain: process.env.COOKIE_DOMAIN,
      httpOnly: true, // document.cookie API로는 사용할 수 없게 만든다(true).
      secure: true, // 오직 HTTPS 연결에서만 사용할 수 있게 만든다(true)
      sameSite: 'none', // 만약 sameSite를 None으로 사용한다면 반드시 secure를 true로 설정해야한다.
      maxAge: 60 * 60 * 1000, // 단위(밀리세컨드), 1h
    });
  res.send('Login successful!');
});

app.get('/protected', (req, res) => {
  // 토큰 검증 로직 생략
  const token = req.cookies.token;

  if (token) {
    // 토큰이 유효한 경우
    res.send('Access granted!');
  } else {
    // 토큰이 없거나 유효하지 않은 경우
    res.send('Access denied!');
  }
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

주의할 점

  1. 보안 고려사항
  • HttpOnly 옵션 설정: XSS(Cross-Site Scripting) 공격으로부터 쿠키를 보호하기 위해 JavaScript에서 쿠키에 접근할 수 없도록 설정해야 합니다. (위 코드 참고)
  • Secure 옵션 설정: HTTPS 연결에서만 쿠키가 전송되도록 하여 통신의 보안성을 강화할 수 있습니다. (위 코드 참고)
  1. 사용사례 및 주의사항
  • 클라이언트와 서버의 시간 동기화: 토큰의 만료 기간을 정확히 설정하기 위해 클라이언트와 서버의 시간 동기화가 필요할 수 있습니다. (NTP: Network Time Protocol 사용)
  • 토큰의 만료 및 갱신 전략: 적절한 토큰 만료 시간과 토큰 갱신 방식을 설정하여 보안성과 사용자 경험을 균형있게 유지해야 합니다.
  • 다중 도메인 처리: 다중 도메인 환경일 경우 쿠키를 유지하기 위해 도메인 간 쿠키 공유 설정을 수행해야 합니다.


결론

특정한 보안 요구사항이나 애플리케이션의 특성에 따라 로컬/세션 스토리지를 활용하는 방식이 더 적합할 수 있습니다. 쿠키는 작은 데이터 조각이므로 토큰의 길이나 쿠키에 저장하는 데이터의 크기가 제한될 수 있고, 여러 도메인을 쓰는 환경일 경우 도메인 공유 설정에도 신경써야 하죠. 하지만 그럼에도 불구하고 보안, 호환성, 서버부하 감소와 확장성, 쉬운 관리등의 장점 때문에 최근 많은 개발자들이 쿠키에 토큰을 담는 방식을 선호하는 것 같습니다.

profile
Look at art, make art, show art and be art. So does as code.

0개의 댓글