Express.js 쿠키 설정 (cookie-parser) 완벽 가이드
Express.js에서 cookie-parser 미들웨어를 사용하여 쿠키를 효과적으로 관리하는 방법을 다룹니다.
Introduction
쿠키는 웹 애플리케이션에서 사용자 상태를 관리하는 중요한 요소입니다. Express.js에서 cookie-parser 미들웨어를 사용하면 쿠키를 쉽게 파싱하고 설정할 수 있습니다.
Environment
npm list express cookie-parser
# express@4.18.2
# cookie-parser@1.4.6
node --version
# v20.11.0Problem
쿠키 설정이 올바르지 않아 보안 문제가 발생했습니다:
// 보안에 문제가 있는 코드
app.get('/login', (req, res) => {
const token = generateToken(user);
// HttpOnly 미설정으로 XSS 공격에 취약
res.cookie('token', token);
// Secure 미설정으로 HTTP에서도 전송
// SameSite 미설정으로 CSRF 공격에 취약
});Solution
1. cookie-parser 기본 설정
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
// cookie-parser 미들웨어
app.use(cookieParser());
// 비밀 키가 있는 서명된 쿠키
app.use(cookieParser('my-secret-key'));
// 라우트에서 쿠키 사용
app.get('/set-cookie', (req, res) => {
res.cookie('name', 'Joel', {
maxAge: 24 * 60 * 60 * 1000, // 1일
});
res.send('Cookie set');
});
app.get('/get-cookie', (req, res) => {
const name = req.cookies.name;
res.json({ name });
});
app.get('/get-signed-cookie', (req, res) => {
const value = req.signedCookies.name;
res.json({ value });
});2. 보안 쿠키 설정
const cookieOptions = {
// 보안 옵션
httpOnly: true, // JavaScript 접근 불가
secure: true, // HTTPS에서만 전송
sameSite: 'strict', // CSRF 공격 방지
maxAge: 24 * 60 * 60 * 1000, // 1일
path: '/', // 쿠키 경로
domain: '.myapp.com', // 도메인
};
// JWT 토큰 쿠키
app.post('/login', async (req, res) => {
const { email, password } = req.body;
const user = await authenticateUser(email, password);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const accessToken = generateAccessToken(user);
const refreshToken = generateRefreshToken(user);
// Access Token은 HttpOnly 쿠키로
res.cookie('accessToken', accessToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 15 * 60 * 1000, // 15분
});
// Refresh Token도 HttpOnly 쿠키로
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000, // 7일
path: '/api/auth', // 특정 경로에서만 접근 가능
});
res.json({ user: { id: user.id, email: user.email } });
});3. 쿠키 기반 세션
const session = require('express-session');
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');
// Redis 클라이언트
const redisClient = createClient();
redisClient.connect();
// 세션 설정
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000,
sameSite: 'strict',
},
}));
// 세션 미들웨어
app.use((req, res, next) => {
// 세션 타임아웃 설정
if (req.session) {
req.session.now = Date.now();
}
next();
});4. 쿠키 유틸리티 함수
class CookieManager {
constructor(res) {
this.res = res;
}
set(name, value, options = {}) {
const defaultOptions = {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
path: '/',
};
this.res.cookie(name, value, { ...defaultOptions, ...options });
return this;
}
get(name) {
return this.req?.cookies?.[name];
}
remove(name, options = {}) {
this.res.clearCookie(name, {
path: '/',
...options,
});
return this;
}
setJSON(name, value, options = {}) {
return this.set(name, JSON.stringify(value), {
...options,
signed: false,
});
}
getJSON(name) {
const value = this.get(name);
try {
return JSON.parse(value);
} catch {
return null;
}
}
}
// Express 미들웨어
function cookieManager(req, res, next) {
req.cookieManager = new CookieManager(req, res);
res.cookieManager = new CookieManager(req, res);
next();
}
app.use(cookieManager);5. 쿠키 정책 설정
// CORS와 쿠키 설정
const cors = require('cors');
app.use(cors({
origin: process.env.ALLOWED_ORIGINS.split(','),
credentials: true, // 쿠키 전송 허용
exposedHeaders: ['Set-Cookie'],
}));
// CSP 헤더에서 쿠키 정책 설정
app.use((req, res, next) => {
res.setHeader('Set-Cookie', [
'SameSite=Strict',
'Secure',
'HttpOnly',
].join('; '));
next();
});Lessons Learned
- 보안 설정 필수: HttpOnly, Secure, SameSite 옵션을 항상 설정하세요
- 서명된 쿠키: 중요한 데이터는 서명된 쿠키를 사용하여 변조를 방지하세요
- 도메인 설정: 프로덕션에서는 도메인을 명확히 설정하세요
- 만료 시간 관리: 쿠키 만료 시간을 적절히 설정하여 보안을 강화하세요
- Redis 세션: 세션 데이터는 Redis에 저장하여 확장성을 확보하세요
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.