이전 포스트에서 세션과 토큰 인증방식에 대해서 알아보며 마지막에 쿠키에 대한 언급을 드렸는데요. 쿠키의 자동전송과 보안성, 지속성등의 대한 이유로 최근에는 토큰을 쿠키에 담는 방식이 많이 사용되고 있습니다. 세션,로컬 스토리지에 저장하지 않고 토큰을 쿠키에 담는 방식이 쓰이는 이유에 대해서 자세히 알아보겠습니다.
쿠키는 크롬이나 사파리 등 웹 사이트가 웹 브라우저에 저장하는 작은 데이터 조각입니다. 이 데이터 조각은 클라이언트와 서버 간의 상호작용을 추적하고, 클라이언트의 상태 정보를 저장하고 전달하는 데 사용됩니다. 일반적으로 쿠키는 이름, 값, 만료 날짜/시간, 도메인 및 경로와 같은 사용자에게 맡겨도 되는 정보만 저장합니다. 더 자세한 설명은 🔗여기에서 확인해 보세요 🙂
보안: 쿠키는 브라우저가 자동으로 관리하기 때문에, 클라이언트에서 직접 토큰을 관리하는 것보다 보안 측면에서 유리합니다. 클라이언트 측에서 토큰을 관리하면, 토큰이 브라우저 내부에서 노출될 수 있는 위험이 있고, 조작당하기 쉽습니다. 하지만 쿠키에 저장된 토큰은 브라우저가 관리하므로, 외부에서 접근하기 어려워 토큰 + 세션/로컬스토리지 방식을 사용했을 때 보다 보안성이 좋습니다.
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');
});
특정한 보안 요구사항이나 애플리케이션의 특성에 따라 로컬/세션 스토리지를 활용하는 방식이 더 적합할 수 있습니다. 쿠키는 작은 데이터 조각이므로 토큰의 길이나 쿠키에 저장하는 데이터의 크기가 제한될 수 있고, 여러 도메인을 쓰는 환경일 경우 도메인 공유 설정에도 신경써야 하죠. 하지만 그럼에도 불구하고 보안, 호환성, 서버부하 감소와 확장성, 쉬운 관리등의 장점 때문에 최근 많은 개발자들이 쿠키에 토큰을 담는 방식을 선호하는 것 같습니다.